HDU 5067 Harry And Dig Machine
题意:有一个n*m的图,每个方格有[0, 100]数量的石子。从(0, 0)出发,到达所有有石子的方格,每个方格都只能经过一次,最终回到(0, 0),两个结点间的距离为曼哈顿距离,问最短路径。
TSP:Traveling Salesman Problem
一个旅行商要拜访n个城市,路径的限制是每个城市只能拜访一次,而且最后要回到原来出发的城市。路径的选择目标是最短路。
图论中著名的问题之一:已给一个n个点的完全图,每条边都有一个长度,求总长度最短的经过每个顶点正好一次的封闭回路。如果两个点之间不存在路径,则增加一条长度为INF的边构成完全图,不影响计算最优回路。
题目中的有石子的方格数量不超过10,所以直接用状压暴力跑所有的状态即可。
dp[now][sta]:当前在位置now,并且之前走过的状态为sta(二进制对应位为1就是走过,对应位为0就是没走过)
状态转移的条件:下一个要走的结点nex没走过,也就是sta | (1 << nex) == 0; 并且当前所在结点走过,也就是sta | (1 << now) == 1
状态转移方程
dp[nex][sta | (1 << nex)] = min(dp[nex][sta | (1 << nex)], dp[now][sta]+dis[now][nex]);
【其中dis[now][nex]为两点间的曼哈顿距离,在之前初始化过的】
最后的结果是位置为0,并且所有点都走过也就是dp[0][(1 << cnt) - 1];
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <limits>
#include <set>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 1e4 + 5;
int n, m;
struct node{
int x, y;
node(int a = 0, int b = 0): x(a), y(b){}
}info[15];
int dp[15][1 << 15];
int dis[15][15];
int main()
{
while(~scanf("%d%d", &n, &m))
{
int cnt = 0;
info[cnt ++ ] = node(0, 0);
for(int i = 0; i < n; i ++ )
{
for(int j = 0; j < n; j ++ )
{
int val; scanf("%d", &val);
if(val == 0 || (i == 0 && j == 0))
continue;
info[cnt ++ ] = node(i, j);
}
}
for(int i = 0; i < cnt; i ++ )//初始化有效点间的曼哈顿距离
for(int j = 0; j < cnt; j ++ )
dis[i][j] = abs(info[i].x - info[j].x) + abs(info[i].y - info[j].y);
memset(dp, INF, sizeof(dp));
for(int i = 0; i < cnt; i ++ )//当前所在位置为i,状态为1 << i的最短路径:就是从点0到点i的距离
dp[i][1 << i] = dis[0][i];
for(int sta = 1; sta < (1 << cnt); sta ++ )//枚举状态:对应位置为1即走过,对应位置为0即未走过
for(int nex = 0; nex < cnt; nex ++ )//枚举下一个位置(更新的也是0->nex的最短路,所以它放到第二层循环)
for(int now = 0; now < cnt; now ++ )//枚举当前所在的位置
if((sta & (1 << now)) && (!(sta & (1 << nex))))//状态转移条件:当前位置在sta里并且下一个位置不在sta里
dp[nex][sta | (1 << nex)] = min(dp[nex][sta | (1 << nex)], dp[now][sta] + dis[now][nex]);
printf("%d\n", dp[0][(1 << cnt) - 1]);
}
return 0;
}
二刷……
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <limits>
#include <set>
#include <queue>
#include <vector>
#include <stack>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 1e4 + 5;
int n, m;
struct node{
int x, y;
node(int a = 0, int b = 0) : x(a), y(b) {}
}info[15];
int dp[15][1 << 15];
int dis[15][15];
int main()
{
while(~scanf("%d%d", &n, &m))
{
int cnt = 0;
info[cnt ++ ] = node(0, 0);
for(int i = 0; i < n; i ++ )
{
for(int j = 0; j < m; j ++ )
{
int val; scanf("%d", &val);
if(val == 0 || (i == 0 && j == 0))
continue;
info[cnt ++ ] = node(i, j);
}
}
for(int i = 0; i < cnt; i ++ )
for(int j = 0; j < cnt; j ++ )
dis[i][j] = abs(info[i].x - info[j].x) + abs(info[i].y - info[j].y);
memset(dp, INF, sizeof(dp));
for(int i = 0; i < cnt; i ++ )
dp[i][1 << i] = dis[0][i];
for(int S = 1; S < (1 << cnt); S ++ )
for(int nex = 0; nex < cnt; nex ++ )
for(int now = 0; now < cnt; now ++ )
if(S & (1 << now) && !(S & (1 << nex)))
dp[nex][S | (1 << nex)] = min(dp[nex][S | (1 << nex)], dp[now][S] + dis[now][nex]);
printf("%d\n", dp[0][(1 << cnt) - 1]);
}
return 0;
}