題目連結:http://acm.hdu.edu.cn/showproblem.php?pid=5067
題意:
給你一個n*m的地圖,地圖上標著對應位置的石子數。你從左上角出發,每次可以向上下左右四個方向移動。你要遍歷所有有石子的地方,並返回起點。問你最少的移動步數。
題解:
簡化問題:
只保留起點和有石子的點,預處理出保留點兩兩之間的最短路(曼哈頓距離),將矩陣轉化為一個無向圖。
原題變為了TSP模板題。
然後套模板就好了。。。
三重for迴圈,分別列舉state、當前位置i、下一步位置j。
AC Code:
1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #include <math.h> 5 #define MAX_N 55 6 #define MAX_S (1<<15) 7 #define INF 10000000 8 9 using namespace std; 10 11 int n,m; 12 int cnt; 13 int ans; 14 int x[MAX_N]; 15 int y[MAX_N]; 16 int dis[MAX_N][MAX_N]; 17 int dp[MAX_S][MAX_N]; 18 19 void read() 20 { 21 cnt=0; 22 int temp; 23 for(int i=0;i<n;i++) 24 { 25 for(int j=0;j<m;j++) 26 { 27 cin>>temp; 28 if(temp>0 || (i==0 && j==0)) 29 { 30 x[cnt]=i; 31 y[cnt]=j; 32 cnt++; 33 } 34 } 35 } 36 } 37 38 void cal_dis() 39 { 40 for(int i=0;i<cnt;i++) 41 { 42 for(int j=0;j<cnt;j++) 43 { 44 dis[i][j]=fabs(x[i]-x[j])+fabs(y[i]-y[j]); 45 } 46 } 47 } 48 49 void solve() 50 { 51 cal_dis(); 52 memset(dp,-1,sizeof(dp)); 53 dp[0][0]=0; 54 for(int state=0;state<(1<<cnt);state++) 55 { 56 for(int i=0;i<cnt;i++) 57 { 58 if(dp[state][i]!=-1) 59 { 60 for(int j=0;j<cnt;j++) 61 { 62 if( !((state>>j)&1) && (dp[state|(1<<j)][j]==-1 || dp[state|(1<<j)][j]>dp[state][i]+dis[i][j]) ) 63 { 64 dp[state|(1<<j)][j]=dp[state][i]+dis[i][j]; 65 } 66 } 67 } 68 } 69 } 70 ans=INF; 71 for(int i=0;i<cnt;i++) 72 { 73 if(dp[(1<<cnt)-1][i]!=-1) ans=min(ans,dp[(1<<cnt)-1][i]+dis[i][0]); 74 } 75 } 76 77 void print() 78 { 79 cout<<ans<<endl; 80 } 81 82 int main() 83 { 84 while(cin>>n>>m) 85 { 86 read(); 87 solve(); 88 print(); 89 } 90 }