http://acm.hdu.edu.cn/showproblem.php?pid=4568
2 3 3 3 2 3 5 4 3 1 4 2 1 1 1 3 3 3 2 3 5 4 3 1 4 2 2 1 1 2 2
8 11
先做的hdu-4571感觉和那题差不多,都需要先处理出任意两点的最短路,不过本题少了一个限制,所以dfs没有很好的终止条件的,然后就不会了...
看了题解后,发现必经点少,可以进行状态压缩储存已经过的点,就想到以前做过更相似的题(hdu-5418),才发现这都是TSP问题
为了方便,增加虚拟的开始与终止节点,不过这样会增加很大的常数
手快打错了,导致又浪费好多时间,找错时想到好多符合题目描述的点,但数据都没有出到...
真是 脑抽1秒钟,调试n小时。
#include <cstdio> #include <cstring> #include <queue> #include <algorithm> using namespace std; const int MAXN=205; const int INF=0x3f3f3f3f; const int dr[4]={-1,0,1,0}; const int dc[4]={0,1,0,-1}; struct Node { int r,c; Node(int rr=0,int cc=0):r(rr),c(cc) {} bool operator < (const Node& a) const { return r<a.r||(r==a.r&&c<a.c); } }p[MAXN]; int n,m,k,STA,DES; int mz[MAXN][MAXN],dis[MAXN*MAXN],cost[15][15],dp[(1<<16)+1][15];//dp[i][j]表示当前i中为1的点已探索过,且最后一个点是j bool vis[MAXN*MAXN]; inline bool isInside(int r,int c) { return 0<=r&&r<n&&0<=c&&c<m; } void Dijkstra(int sta) { int r,c,rr,cc,tmp; Node u; priority_queue<Node> q; tmp=p[sta].r*m+p[sta].c; q.push(Node(0,tmp));//偷懒,用r代表当前点与sta的距离,c代表当前点 memset(dis,0x3f,sizeof(dis)); memset(vis,false,sizeof(vis)); dis[tmp]=0;//dis[tmp]表示sta点到tmp点的距离,不包括sta点的花费,包括tmp点的花费 while(!q.empty()) { do { u=q.top(); q.pop(); } while(!q.empty()&&vis[u.c]); if(vis[u.c]) return ; vis[u.c]=true; dis[u.c]=-u.r; r=u.c/m; c=u.c%m; for(int i=0;i<4;++i) { rr=r+dr[i]; cc=c+dc[i]; tmp=rr*m+cc; if(isInside(rr,cc)&&!vis[tmp]&&mz[rr][cc]!=-1) q.push(Node(-dis[u.c]-mz[rr][cc],tmp)); } } } int main() { int T,mn,t,kk; scanf("%d",&T); while(T-->0) { scanf("%d%d",&n,&m); for(int i=0;i<n;++i) for(int j=0;j<m;++j)//最开始m写成n,查了好久错... scanf("%d",&mz[i][j]); scanf("%d",&k); STA=0; DES=k+1; for(int i=1;i<=k;++i) scanf("%d%d",&p[i].r,&p[i].c); memset(cost,0x3f,sizeof(cost)); for(int i=1;i<=k;++i) { Dijkstra(i); for(int j=1;j<=k;++j) cost[i][j]=dis[p[j].r*m+p[j].c]; mn=INF; for(int j=0;j<n;++j) mn=min(mn,min(dis[j*m],dis[j*m+m-1])); t=n*m-m; for(int j=0;j<m;++j) mn=min(mn,min(dis[j],dis[t+j])); cost[i][DES]=mn;//出去的最小花费即该点到边界的最小花费 cost[STA][i]=mz[p[i].r][p[i].c]+mn;//此处要包含探索i的花费 } k+=2; kk=1<<k; memset(dp,0x3f,sizeof(dp)); dp[1<<STA][STA]=0; for(int i=0;i<kk;++i) for(int j=0;j<k;++j) if(((i>>j)&1)==1) for(int l=0;l<k;++l) dp[i][j]=min(dp[i][j],dp[i&(~(1<<j))][l]+cost[l][j]); printf("%d\n",dp[kk-1][DES]==INF?0:dp[kk-1][DES]); } return 0; }