首页 > 其他分享 >题解:SP10242 ACPC11D - Dice on a Board

题解:SP10242 ACPC11D - Dice on a Board

时间:2024-10-02 17:49:13浏览次数:7  
标签:pq dist int 题解 300 bool Board ACPC11D 朝向

思路

递归生成所有的可能的筛子朝向,用 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;
}

标签:pq,dist,int,题解,300,bool,Board,ACPC11D,朝向
From: https://www.cnblogs.com/cly312/p/18444912

相关文章

  • 题解:P9954 [USACO20OPEN] Cowntact Tracing B
    考虑暴力。枚举让每头牛都当一次“零号病人”和\(K\)的所有组合,模拟感染的过程,检查得出的病人是否和给出的一样即可。代码:#include<bits/stdc++.h>usingnamespacestd;boolinfectedd[101];intN,cowx[251],cowy[251];boolcheck(intpatient_zero,intK){ boolinfect......
  • 题解:SP9934 ALICE - Alice and Bob
    状态表示:使用两个变量来表示当前游戏的状态:\(a\)表示包含\(1\)个石子的堆的数量,\(b\)表示包含多于\(1\)个石子的堆的可操作次数。游戏策略:从包含多个石子的堆中取走一个石子,这会减少\(b\)。从包含\(1\)个石子的堆中取走一个石子,这会减少\(a\)。合......
  • 题解:P9939 [USACO21OPEN] Acowdemia III B
    考虑贪心。遍历每只奶牛:如果它最多与一头奶牛相邻,那么什么都不会发生。如果它与两头以上的奶牛相邻,那么它与两侧的两头奶牛相邻。将答案递增\(1\)。否则,如果正好有两头相邻的奶牛,我们就把它们配对。也就是说,将这对奶牛插入一组。代码:#include<bits/stdc++.h>usingname......
  • 题解:UVA1500 Alice and Bob
    状态表示:使用两个变量来表示当前游戏的状态:\(a\)表示包含\(1\)个石子的堆的数量,\(b\)表示包含多于\(1\)个石子的堆的可操作次数。游戏策略:从包含多个石子的堆中取走一个石子,这会减少\(b\)。从包含\(1\)个石子的堆中取走一个石子,这会减少\(a\)。合......
  • 题解:P9788 [ROIR 2020 Day2] 区域规划
    法1枚举\(a,b,c\),考虑到\(c\)的最小值为\(\max(1,\frac{(a\cdotb−n)}{b})\),所以直接剪枝即可通过。代码:#include<bits/stdc++.h>usingnamespacestd;intans,n,m;intmain(){ ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin>>n>>m; for(i......
  • 题解:UVA124 Following Orders
    考虑深搜和拓扑排序。从入度为零的节点开始,逐步添加到当前的排列结果中,并在每一步递减相邻节点的入度。如果某个节点的入度变为零,就递归地将其添加到当前排列中。一旦达到排列的叶节点,就存储起来,并按字典顺序排序。代码:#include<bits/stdc++.h>usingnamespacestd;voidread......
  • 题解:UVA117 The Postal Worker Rings Once
    此题要求我们求欧拉回路的长度。使用Floyd算法计算图中任意两点之间的最短路径,对于度数为奇数的路口(最多有两个),找到它们之间的最短路径并将其加入总路径长度中。代码:#include<bits/stdc++.h>#defineINF1e8usingnamespacestd;intdegree[26];intpath[26][26];intal......
  • 题解:SP15553 STC00 - Hamsters
    首先,通过预处理计算每个名字的哈希值,然后利用哈希检查名字之间的最长公共前缀,从而确定从一个名字转移到另一个名字的最小代价。使用倍增动态规划计算转移的最小成本,\(f_{t,i,j}\)表示从名字\(i\)经过\(2^t\)步转移到名字\(j\)的最小代价,最后通过位运算处理\(M\)次转移的......
  • 题解:AT_abc373_d [ABC373D] Hidden Weights
    可以发现一个性质:对于图的每个连通分量,一旦在其中任何顶点上的值固定,则所有写入的值都是确定的。我们可以逐个DFS每个连通分量,按照题目的要求给每个点赋值,初始搜索的点值设成\(0\)即可。代码:#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intn,m;......
  • 题解:SP19382 STK - Stock
    一道动态规划题。先分析状态。\(dp_{i\operatorname{and}1,k}\):表示在第\(i\)天最多进行\(k\)次交易的最大利润。\(s_{i\operatorname{and}1,k}\):表示在第\(i\)天之前的某天卖出之后,最多进行\(k-1\)次交易的最大利润减去当天的价格。接下来分析转移方程当\(i=0\)......