题意:
裸的tsp。
分析:
用bfs求出任意两点之间的距离后可以暴搜也可以用next_permutation水,但效率肯定不如状压dp。dp[s][u]表示从0出发访问过s集合中的点,目前在点u走过的最短路程。
代码:
//poj 2688 //sep9 #include <iostream> #include <queue> using namespace std; const int maxW=32; const int maxN=12; int dx[4]={-1,1,0,0}; int dy[4]={0,0,-1,1}; char graph[maxW][maxW]; int g[maxW][maxW]; int vis[maxW][maxW]; int d[maxN][maxN]; int n,w,h; int dp[1<<maxN][maxN]; struct Node{ int x,y; }dirty_pnt[maxN]; void bfs(int s) { memset(vis,-1,sizeof(vis)); queue<Node> Q; Q.push(dirty_pnt[s]); vis[dirty_pnt[s].x][dirty_pnt[s].y]=0; while(!Q.empty()){ Node q=Q.front();Q.pop(); int x=q.x,y=q.y; for(int i=0;i<4;++i){ int nx=x+dx[i]; int ny=y+dy[i]; if(nx>=0&&nx<h&&ny>=0&&ny<w&&g[nx][ny]>=0&&vis[nx][ny]==-1){ vis[nx][ny]=vis[x][y]+1; Node p; p.x=nx,p.y=ny; Q.push(p); } } } } int rec(int s,int u){ if(dp[s][u]!=-1) return dp[s][u]; int i,j,res=INT_MAX; int ss=s&(~(1<<u)); for(i=0;i<n;++i) if(ss>>i&1) res=min(res,rec(ss,i)+d[i+1][u+1]); return dp[s][u]=res; } int main() { int i,j,k; while(scanf("%d%d",&w,&h)==2&&(w+h)){ for(i=0;i<h;++i) scanf("%s",graph[i]); n=0; for(i=0;i<h;++i) for(j=0;j<w;++j){ if(graph[i][j]=='*'){ g[i][j]=++n; dirty_pnt[n].x=i; dirty_pnt[n].y=j; } else if(graph[i][j]=='.') g[i][j]=0; else if(graph[i][j]=='o'){ g[i][j]=0; dirty_pnt[0].x=i; dirty_pnt[0].y=j; }else g[i][j]=-1; } int not_reach=0; for(k=0;k<=n&&!not_reach;++k){ bfs(k); for(i=0;i<=k;++i){ d[k][i]=d[i][k]=vis[dirty_pnt[i].x][dirty_pnt[i].y]; if(d[k][i]==-1){ not_reach=1; break; } } } // for(i=0;i<=n;++i) // for(j=0;j<=n;++j){ // printf("%d %d==%d\n",i,j,d[i][j]); // } if(not_reach==1){ printf("-1\n"); continue; } memset(dp,-1,sizeof(dp)); int ans=INT_MAX; for(i=0;i<n;++i) dp[1<<i][i]=d[0][i+1]; for(i=0;i<n;++i) ans=min(ans,rec((1<<n)-1,i)); printf("%d\n",ans); } return 0; }
原文地址:http://blog.csdn.net/sepnine/article/details/44274493