5 4 ....# ...#. ..... ..... ..... 2 3 1 4 1 2 3 5 2 3 3 1 5 4 2 1
7
链接:http://acm.hdu.edu.cn/showproblem.php?pid=4856
题意:给你一个n*n地图,再给你m个有向通道,每个通道走的时间为0,走格子的时间为1,问最短多少时间走完所有通道,所有通道要求走 有且仅有一次 。
做法:
dis[i][j] 代表i的通道出口到j的通道入口要走多少步。
dp[i][j],i是二进制代表每个通道走过没有,j代表最后一个走的通道。dp值为完成这个状态最少的步数。
dp[i|(1<<k)][k]=min(dp[i|(1<<k)][k],dp[i][j]+dis[j][k]);这个是转移公式,从j通道的出口到k通道的入口
然后更新一遍,把i==(1<<m)-1的 所有最后所在地遍历一遍,求个最小值就行了。
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <limits.h> #include <malloc.h> #include <ctype.h> #include <math.h> #include <string> #include <iostream> #include <algorithm> using namespace std; #include <stack> #include <queue> #include <vector> #include <deque> #include <set> #include <sstream> #define eps 0.00001 #define LL __int64 #define pi acos(-1.0) #define INF 0x1f1f1f1f1f int n,m; struct lujin { int x1,y1,x2,y2; }; lujin pkk[20]; char mp[20][20]; struct node { int x,y; int bu; }; node dian; int ok(int xx,int yy) { if(xx<0||xx>=n||yy<0||yy>=n||mp[xx][yy]=='#') return 0; return 1; } int dir[4][2]={{1,0},{-1,0},{0,1},{0,-1}}; int viss[20][20]; int len(int i,int j)//i终点 j起点 { queue <node> q; node nw,sta,ee,nxt; sta.x=pkk[i].x2,sta.y=pkk[i].y2; sta.bu=0; ee.x=pkk[j].x1,ee.y=pkk[j].y1; ee.bu=0; q.push(sta); memset(viss,0,sizeof viss); viss[sta.x][sta.y]=1; while(!q.empty()) { nw=q.front(); q.pop(); if(nw.x==ee.x&&nw.y==ee.y) return nw.bu; for(int i=0;i<4;i++) { int xx=nw.x+dir[i][0]; int yy=nw.y+dir[i][1]; nxt.x=xx; nxt.y=yy; nxt.bu=nw.bu+1; if(ok(xx,yy)&&viss[xx][yy]==0) { viss[xx][yy]=1; q.push(nxt); } } } return INF; } int dp[1<<16][16];//这个状态 最后一个到达点 int dis[20][20]; int main() { while(scanf("%d%d",&n,&m)!=EOF) { for(int i=0;i<n;i++) scanf("%s",mp[i]); for(int i=0;i<m;i++) { int x,y; scanf("%d%d",&x,&y); pkk[i].x1=x-1; pkk[i].y1=y-1; scanf("%d%d",&x,&y); pkk[i].x2=x-1; pkk[i].y2=y-1; } if(m==1) { printf("%d\n",0); continue; } for(int i=0;i<m;i++) { for(int j=0;j<m;j++) dis[i][j]=len(i,j);//i尾 到j头 } memset(dp,0x1f1f1f1f1f,sizeof dp); for(int i=0;i<m;i++) dp[1<<i][i]=0; for(int i=1;i<(1<<m)-1;i++) { for(int j=0;j<m;j++)//最后一个点 { if((i&(1<<j))) for(int k=0;k<m;k++)//tou { if((i&(1<<k))==0)//还没有走过 dp[i|(1<<k)][k]=min(dp[i|(1<<k)][k],dp[i][j]+dis[j][k]); } } } int ans=INF; for(int i=0;i<m;i++) { ans=min(ans,dp[(1<<m)-1][i]); } int ttt=INF; if(ans==ttt) printf("-1\n"); else printf("%d\n",ans); } return 0; }