题意大致是说给你一个矩阵,其中某些位置有一些宝藏,让你尽可能的取出宝藏并花费最少的代价。矩阵中为-1的是不能走的,另外走的代价为你经过格子的值,你可以选择任意地点进入与出来。
思路:我先用的Spfa把所有宝藏之间的最短距离算出来,并算出从当前宝藏离开的最短路径。然后就是类似于TSP的DP了,需要注意的是处理-1的情况,也比较简单。后面的转移方程式为dp[j][i]=min(dp[j][k]+dis[k][i]) 其中dp[j][i]表示当前位置在j,得到的宝藏状态为i还需要多少代价完成拿所有的能拿的宝藏。
代码:
#include<cstdio> #include<cstring> #include<iostream> #include<queue> using namespace std; const int inf=1<<29; const int maxn=210; int movex[4]={1,-1,0,0},movey[4]={0,0,1,-1}; int n,m,k,a[maxn][maxn],fx[16],fy[16],fo[maxn][maxn],dist[maxn*maxn],dis[16][16]; int dp[16][1<<13]; bool vis[maxn*maxn]; queue<int> q; void Init() { memset(fo,0,sizeof(fo)); } bool isborder(int x,int y) { if(x<0||y<0||x>=n||y>=m) return true; return false; } void Spfa(int sx,int sy) { for(int i=0;i<=m*n;i++) dist[i]=inf; if(a[sx][sy]==-1) return; dist[sx*m+sy]=0; q.push(sx*m+sy); while(!q.empty()) { int u=q.front(); vis[u]=0; q.pop(); for(int i=0;i<4;i++) { int itx=u/m+movex[i]; int ity=u%m+movey[i]; if(isborder(itx,ity)) { dist[n*m]=min(dist[n*m],dist[u]); } else if(a[itx][ity]!=-1) { if(dist[itx*m+ity]>dist[u]+a[itx][ity]) { dist[itx*m+ity]=dist[u]+a[itx][ity]; if(!vis[itx*m+ity]) { q.push(itx*m+ity); vis[itx*m+ity]=1; } } } } } } void solve() { for(int i=1;i<=k;i++) { Spfa(fx[i],fy[i]); for(int j=1;j<=k;j++) dis[i][j]=dist[fx[j]*m+fy[j]]; dis[i][k+1]=dist[n*m]; } int res=k,fin=(1<<k)-1; bool is=false; if(k>1) { for(int i=1;i<=k;i++) { for(int j=1;j<=k;j++) if(i!=j&&dis[i][j]!=inf) { is=true; break; } if(!is) { res--; fin^=(1<<(i-1)); } } } for(int i=1;i<=k;i++) for(int j=0;j<=fin;j++) dp[i][j]=inf; for(int i=1;i<=k;i++) dp[i][1<<(i-1)]=dis[i][k+1]+a[fx[i]][fy[i]]; for(int i=0;i<=fin;i++) for(int j=1;j<=k;j++) for(int l=1;l<=k;l++) if(l!=j&&(!(i&(1<<(l-1))))) dp[l][i|(1<<(l-1))]=min(dp[l][i|(1<<(l-1))],dp[j][i]+dis[j][l]); int ans=inf; for(int i=1;i<=k;i++) ans=min(ans,dp[i][fin]+dis[i][k+1]); if(ans==inf) printf("0\n"); else printf("%d\n",ans); } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); for(int i=0;i<n;i++) for(int j=0;j<m;j++) scanf("%d",&a[i][j]); scanf("%d",&k); for(int i=1;i<=k;i++) { scanf("%d%d",&fx[i],&fy[i]); fo[fx[i]][fy[i]]=i; } solve(); } return 0; }