HDU 4568 Hunter(最短路径+DP)(2013 ACM-ICPC长沙赛区全国邀请赛)
Problem Description
One day, a hunter named James went to a mysterious area to find the treasures. James wanted to research the area and brought all treasures that he could.
The area can be represented as a N*M rectangle. Any points of the rectangle is a number means the cost of research it,-1 means James can't cross it, James can start at any place out of the rectangle, and explore point next by next. He will move in the rectangle and bring out all treasures he can take. Of course, he will end at any border to go out of rectangle(James will research every point at anytime he cross because he can't remember whether the point are researched or not).
Now give you a map of the area, you must calculate the least cost that James bring out all treasures he can take(one point up to only one treasure).Also, if nothing James can get, please output 0.
![](http://acm.hdu.edu.cn/data/images/C468-1004-1.jpg)
The area can be represented as a N*M rectangle. Any points of the rectangle is a number means the cost of research it,-1 means James can't cross it, James can start at any place out of the rectangle, and explore point next by next. He will move in the rectangle and bring out all treasures he can take. Of course, he will end at any border to go out of rectangle(James will research every point at anytime he cross because he can't remember whether the point are researched or not).
Now give you a map of the area, you must calculate the least cost that James bring out all treasures he can take(one point up to only one treasure).Also, if nothing James can get, please output 0.
![](http://acm.hdu.edu.cn/data/images/C468-1004-1.jpg)
Input
The input consists of T test cases. The number of test cases T is given in the first line of the input. Each test case begins with a line containing 2 integers N M , (1<=N,M<=200), that represents the rectangle. Each of the following N lines contains M numbers(0~9),represent the cost of each point. Next is K(1<=K<=13),and next K lines, each line contains 2 integers x y means the position of the treasures, x means row and start from 0, y means column start from 0 too.
Output
For each test case, you should output only a number means the minimum cost.
题目大意:一个n*m的格子,每个格子有一个花费cost,如果花费是-1代表格子不能走。现在格子里有K个宝藏,问拿齐K个宝藏的最小花费,只能进出一次。
思路:首先,注意到K很小,还是一个很奇葩的数字。所以,其实这题的路径就是要走遍这K个点的最短路,这就是经典的TSP问题,位DP解决。需要预处理出每个点到其他点的最短路径,把矩阵外看成一个点(在我的代码里标号为K),对每个点做单源最短路径即可。
PS:这题有说,如果拿不到任何宝藏输出0,其实这条件是没用的……这题的描述有一点坑爹,如果你有一些宝藏能拿到,有一些宝藏不能拿到(被一堆-1围着),那我要输出啥?经测试根本就没有这种东西……因为都是有答案的所以根本就不需要考虑宝藏所在点是-1和点点之间不连通这种坑爹的问题了。
PS2:我做这题的时候没看到-1,然后Dijkstra+heap不断MLE,后来加了个vis判是否出队的问题,就WA了……之前一直没想明白为什么会出现MLE的情况,看来是-1加了进去有无穷多的数进队导致……
代码(171MS):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <queue> 3 #include <utility> 4 #include <iostream> 5 #include <cstring> 6 using namespace std; 7 typedef pair<int, int> PII; 8 9 const int MAXN = 205; 10 11 int mat[MAXN][MAXN], tx[15], ty[15]; 12 int dis[MAXN][MAXN], di[15][15]; 13 bool ist[MAXN][MAXN]; 14 int post[MAXN][MAXN]; 15 int n, m, k; 16 17 #define pos(x, y) (x*MAXN+y) 18 19 int fx[4] = {-1,0,1,0}; 20 int fy[4] = {0,1,0,-1}; 21 22 void min_path(int st_x, int st_y, int now) { 23 priority_queue<PII> que; 24 que.push(make_pair(-mat[st_x][st_y], pos(st_x, st_y))); 25 memset(dis, 0x3f, sizeof(dis)); 26 dis[st_x][st_y] = mat[st_x][st_y]; 27 while(!que.empty()) { 28 int abc = -que.top().first, tmp = que.top().second; que.pop(); 29 int x = tmp / MAXN, y = tmp % MAXN; 30 if(abc != dis[x][y]) continue; 31 for(int i = 0; i < 4; ++i) { 32 int newx = x + fx[i], newy = y + fy[i]; 33 if(0 <= newx && newx < n && 0 <= newy && newy < m) { 34 if(mat[newx][newy] == -1) continue; 35 if(dis[newx][newy] > mat[newx][newy] + dis[x][y]) { 36 dis[newx][newy] = mat[newx][newy] + dis[x][y]; 37 que.push(make_pair(-dis[newx][newy], pos(newx, newy))); 38 if(ist[newx][newy] && dis[newx][newy] < di[now][post[newx][newy]]) 39 di[now][post[newx][newy]] = dis[newx][newy]; 40 } 41 } 42 else if(dis[x][y] < di[now][k]) di[now][k] = dis[x][y]; 43 } 44 } 45 } 46 47 int dp[14][20000]; 48 int ans, sum; 49 50 int dfs(int u, int use) { 51 if(dp[u][use] < 0x3f3f3f3f) return dp[u][use]; 52 if(use == 0) { 53 return dp[u][use] = di[u][k]; 54 } 55 for(int i = 0; i < k; ++i) { 56 if(use & (1 << i)) 57 dp[u][use] = min(dp[u][use], di[u][i] + dfs(i, use ^ (1 << i))); 58 } 59 return dp[u][use]; 60 } 61 62 void solve() { 63 memset(dp, 0x3f, sizeof(dp)); 64 ans = 0x7fff7fff; 65 for(int i = 0; i < k; ++i) 66 ans = min(ans, di[i][k] + dfs(i, (1 << i) ^ ((1 << k) - 1))); 67 } 68 69 void printdi() { 70 for(int i = 0; i < k; ++i) { 71 for(int j = 0; j <= k; ++j) printf("%d ", di[i][j]); 72 printf("\n"); 73 } 74 } 75 76 int main() { 77 int T; 78 scanf("%d", &T); 79 while(T--) { 80 scanf("%d%d", &n, &m); 81 for(int i = 0; i < n; ++i) 82 for(int j = 0; j < m; ++j) scanf("%d", &mat[i][j]); 83 scanf("%d", &k); 84 memset(ist, 0, sizeof(ist)); 85 sum = 0; 86 for(int i = 0; i < k; ++i) { 87 scanf("%d%d", &tx[i], &ty[i]); 88 ist[tx[i]][ty[i]] = true; 89 post[tx[i]][ty[i]] = i; 90 sum += mat[tx[i]][ty[i]]; 91 } 92 memset(di, 0x3f, sizeof(di)); 93 for(int i = 0; i < k; ++i) min_path(tx[i], ty[i], i); 94 //printdi(); 95 solve(); 96 printf("%d\n", ans - sum); 97 } 98 }