题解:SP10242 ACPC11D - Dice on a Board

思路

递归生成所有的可能的筛子朝向,用 DFS 标记所有可达的位置,用 dijkstra 计算从起始位置到目标位置的最优路径,并确定在移动过程中能够获得的最大分数。

generate 函数

generate 用于生成所有可能的骰子朝向排列, \(mask\) 作为参数,用于表示哪些数字已经被使用。使用二进制压缩。使用函数 __builtin_popcount 用于求出二进制下一共有多少个 \(1\)

完整代码:

#include<bits/stdc++.h>
using namespace std;
struct Node {
    int u,k,dist;
    Node(int u,int k,int dist) : u(u),k(k),dist(dist){}
    bool operator<(const Node &other) const {
        return dist>other.dist;
    }
};
int dm[4][6]={
    {4,5,2,3,1,0},
    {5,4,2,3,0,1},
    {0,1,5,4,2,3},
    {0,1,4,5,3,2}
};
int dx[4]={0,0,1,-1};
int dy[4]={1,-1,0,0};
vector<int> adj[720];//每个朝向在四个方向移动后的新朝向。
bool v[300][300];
char g[300][300];
int n,m;
unordered_map<string,int> mp;
string mpp[720];
char perm[6];
int sz=0;
bool valid(int nx,int ny){
    return nx>-1&&nx<n&&ny>-1&&ny<m&&g[nx][ny]!='.'&&g[nx][ny]!='S';
}
string move(const string &s,int d){
    char t[6];
    for(int i=0;i<6;i++)
        t[i]=s[dm[d][i]];
    return string(t,6);
}
void dfs(int x,int y){
    v[x][y]=true;
    for(int i=0;i<4;i++){
        int nx=x+dx[i];
        int ny=y+dy[i];
        if(valid(nx,ny)&&!v[nx][ny])
            dfs(nx,ny);
    }
}
int get(int nx,int ny,int c){
    if(g[nx][ny]=='T')
        return 0;
    int nc=g[nx][ny]-'0';
    if(nc==c)
        return -c*2;
    return c+nc;
}
void generate(int mask){
    if(mask==63){
        string s(perm,6);
        mp[s]=sz;
        mpp[sz++]=s;
        return;
    }
    for(int i=0;i<6;i++){
        if(!(mask &(1 << i))){
            perm[__builtin_popcount(mask)]=i+1+'0';
            generate(mask|(1 << i));
        }
    }
}
void dijkstra(int s,int st,int e){
    vector<vector<int>> dist(n*m,vector<int>(720,INT_MAX));
    dist[s][st]=0;
    priority_queue<Node> pq;
    pq.emplace(s,st,0);
    bool flag=false;
    while(!pq.empty()&&!flag){
        Node t=pq.top();
        pq.pop();
        if(t.u==e)
            continue;
        if(t.dist==dist[t.u][t.k]){
            int x=t.u/m;
            int y=t.u%m;
            for(int i=0;i<4;i++){
                int nx=x+dx[i];
                int ny=y+dy[i];
                if(valid(nx,ny)){
                    int idx=adj[t.k][i];
                    int cost=get(nx,ny,mpp[idx][5]-'0');
                    if(g[x][y]!='S'&&g[nx][ny]!='T'){
                        int prev=get(x,y,mpp[t.k][5]-'0');
                        if(prev+cost<0)
                            flag=true;
                    }
                    if(dist[t.u][t.k]+cost<dist[nx*m+ny][idx]){
                        dist[nx*m+ny][idx]=dist[t.u][t.k]+cost;
                        pq.emplace(nx*m+ny,idx,dist[nx*m+ny][idx]);
                    }
                }
            }
        }
    }
    if(flag){
        cout<<"Infinity\n";
        return;
    }
    int minDist=INT_MAX;
    for(int k=0;k<720;k++)
        minDist=min(minDist,dist[e][k]);
    cout<<-minDist<<'\n';
}

int main(){
    generate(0);
    for(const auto &p:mp){
        int idx=p.second;
        adj[idx].resize(4);
        for(int i=0;i<4;i++)
            adj[idx][i]=mp[move(p.first,i)];
    }
    int tc;
    cin>>tc;
    while(tc--){
        cin>>n>>m;
        string dice;
        cin>>dice;
        for(int i=0;i<n;i++)
            for(int j=0;j<m;j++)
                cin>>g[i][j];
        memset(v,0,sizeof(v));
        int si=0,sj=0,ti=0,tj=0;
        for(int i=0;i<n;i++){
            for(int j=0;j<m;j++){
                if(g[i][j]=='S'){
                    si=i;
                    sj=j;
                } else if(g[i][j]=='T'){
                    ti=i;
                    tj=j;
                }
            }
        }
        dfs(si,sj);
        if(!v[ti][tj]){
            cout<<"Impossible\n";
            continue;
        }
        dijkstra(si*m+sj,mp[dice],ti*m+tj);
    }
    return 0;
}
posted @ 2024-10-02 17:41  cly312  阅读(22)  评论(0)    收藏  举报