https://icpcarchive.ecs.baylor.edu/external/64/6455.pdf
题意:求从起点走遍所有k个点所需的中最小步数,算是状态压缩搜索的经典题目了。
分析:状态即为已走过点的情况,一个int型可以搞定。有一个小技巧,一般状态压缩的题目主要的属性一般不超过32或64个点
代码:
#include<iostream> #include<cstdio> #include<cmath> #include<queue> #include<set> #include<cstring> #include<algorithm> #define LL long long #define MOD 100000007 #define INF 0x3f3f3f3f using namespace std; const int maxn=105; char g[maxn][maxn]; int opp[maxn][maxn]; bool done[maxn][maxn][16]; int n,m,k,sx,sy; int dx[]={0,0,-1,1}; int dy[]={-1,1,0,0}; struct node { int x,y,w,key; node(int xx=0,int yy=0,int ww=0,int cc=0) { x=xx;y=yy;w=ww;key=cc; } }; bool is_ill(int x,int y) { return x<0||x>=n||y<0||y>=m; } int bfs() { queue<node>q; memset(done,0,sizeof done); q.push(node(sx,sy,0,k)); done[sx][sy][k]=1; while(!q.empty()) { node x=q.front();q.pop(); for(int i=0;i<4;i++) { int curx=x.x+dx[i]; int cury=x.y+dy[i]; int curkey=x.key; if(is_ill(curx,cury)||g[curx][cury]=='#')continue; if(opp[curx][cury]==-1&&done[curx][cury][curkey])continue; if(x.key&(1<<opp[curx][cury]))curkey^=(1<<opp[curx][cury]); if(done[curx][cury][curkey])continue; if(curkey==0)return x.w+1; q.push(node(curx,cury,x.w+1,curkey)); done[curx][cury][curkey]=1; //printf("%d %d %d %d\n",curx,cury,x.w+1,curkey); } } return -1; } int main() { int a,b,kk; while(~scanf("%d%d",&n,&m)&&(n||m)) { for(int i=0;i<n;i++) scanf("%s",g[i]); scanf("%d",&kk); if(kk==0) { printf("0\n"); continue; } int aa=0;k=0; memset(opp,-1,sizeof opp); for(int i=0;i<kk;i++) scanf("%d%d",&a,&b),a--,b--,k|=(1<<i),opp[a][b]=i; for(int i=0;i<n;i++) for(int j=0;j<m;j++) if(g[i][j]=='@')sx=i,sy=j; printf("%d\n",bfs()); } return 0; }