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