标签:
一个N*M的迷宫,每个点有代价,代价为-1时表示不能走到,迷宫中有k个宝藏,求取走所有宝藏所需要的最小代价,只能进入迷宫一次
计算出所有宝藏之间的最短距离及从该宝藏出迷宫的最短距离,然后做状压DP即可
#include "stdio.h" #include "string.h" #include "queue" using namespace std; struct node { int x,y,cost; bool friend operator<(node n1,node n2) { return n2.cost<n1.cost; } }; const int inf=0x3f3f3f3f; const int dir[4][2]={ {1,0},{-1,0},{0,1},{0,-1} }; int n,m,k,tot; int dis[20][20],mark[210][210],a[210][210],b[20],x[20],y[20]; // mark记录点是否存在宝藏并记录编号,dis记录宝藏间最短距离 int used[210][210],dp[70000][20]; // dp[i][j]=i状态,以j点为最终结点的最小代价 int Min(int a,int b) { if (a<b) return a; else return b; } int judge(int x,int y) { if (x<0 || y<0 || x>=n || y>=m) return 0; if (used[x][y]!=0) return 0; if (a[x][y]==-1) return 0; return 1; } void bfs(int w) { priority_queue<node>q; node cur,next; int i; memset(used,0,sizeof(used)); cur.x=x[w]; cur.y=y[w]; cur.cost=0; if (cur.x==0 || cur.y==0 || cur.x==n-1 || cur.y==m-1) // 是否在边界,在边界则记录到0号点距离 dis[w][0]=dis[0][w]=dis[w][k+1]=dis[k+1][w]=0; used[cur.x][cur.y]=1; q.push(cur); while (!q.empty()) { cur=q.top(); q.pop(); for (i=0;i<4;i++) { next.x=cur.x+dir[i][0]; next.y=cur.y+dir[i][1]; if (judge(next.x,next.y)==0) continue; next.cost=cur.cost+a[next.x][next.y]; used[next.x][next.y]=1; if (next.x==0 || next.y==0 || next.x==n-1 || next.y==m-1) { dis[w][0]=dis[0][w]=Min(dis[w][0],next.cost); dis[w][k+1]=dis[k+1][w]=dis[w][0]; } if (mark[next.x][next.y]!=0) { dis[w][mark[next.x][next.y]]=Min(dis[w][mark[next.x][next.y]],next.cost-a[next.x][next.y]); dis[mark[next.x][next.y]][w]=dis[w][mark[next.x][next.y]]; } q.push(next); } } } void DP() { int i,j,l; memset(dp,inf,sizeof(dp)); dp[1][0]=0; for (i=0;i<=tot;i++) for (j=0;j<=k+1;j++) if ( (b[j]&i)!=0 && dp[i][j]!=-1) for (l=0;l<=k+1;l++) if (l!=j && (b[l]&i)==0) dp[i+b[l]][l]=Min(dp[i+b[l]][l],dp[i][j]+dis[j][l]); } int main() { int t,i,j,ans; b[0]=1; for (i=1;i<=16;i++) b[i]=b[i-1]*2; scanf("%d",&t); while (t--) { scanf("%d%d",&n,&m); for (i=0;i<n;i++) for (j=0;j<m;j++) scanf("%d",&a[i][j]); scanf("%d",&k); memset(mark,0,sizeof(mark)); for (i=1;i<=k;i++) { scanf("%d%d",&x[i],&y[i]); mark[x[i]][y[i]]=i; } memset(dis,inf,sizeof(dis)); for (i=1;i<=k;i++) bfs(i); // 计算所有宝藏间的最短距离及与边界的最短距离 tot=b[k+2]-1; DP(); // 状压DP ans=dp[tot][k+1]; for (i=1;i<=k;i++) ans+=a[x[i]][y[i]]; printf("%d\n",ans); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
标签:
原文地址:http://blog.csdn.net/u011932355/article/details/47057135