【cofun1372】售货员难题
Description
某乡有n个村庄(1<=n<=14),有一个售货员,他要到各个村庄去售货,各村庄之间的路程s(0< s<1000)是已知的,且A村到B村与B村到A村的路程大多不同。为了提高效率,他从商店出发到每个村庄一次,然后返回商店所在地,假设商店所在的村庄为1,他不知道选择什么样的路线才能使所走的路程之和最短。请你帮他选择一条最短的路。
Input Format
村庄数n和各村之间的路程(均是正整数)。
Output Format
最短的路程
Sample Input
4 {村庄数}
0 30 6 4 {村庄1到各村的路程}
30 0 5 10 {村庄2到各村的路程}
6 5 0 20 {村庄3到各村的路程}
4 10 20 0 {村庄4到各村的路程}
Sample Output
25
- 分析:
- n <= 14
一般来说 情况 <= 20 都要考虑一下状压DP。
用二进制存储村庄(0: 没去过/ 1: 去过)。 - 转移方程:
- n <= 14
f[i | (1 << k)][k] = min(f[i | (1 << k)][k], f[i][j] + dist[j][k]);
f[i][j] : 状态为i,最后走到 j 村庄的最短路程;
dist[j][k] : j和k之间的路程
【算得上状压裸题。。吧XDD
- 代码:
#include <bits/stdc++.h>
using namespace std;
int n, i, j, k, dist[15][15], f[1 << 16][16];
int main()
{
scanf("%d", &n);
for(i = 0; i < n; i ++)
for(j = 0; j < n; j ++)
scanf("%d", &dist[i][j]);
//读入
memset(f, 0x3f, sizeof(f));
for(i = 0; i < n; i ++)
f[1 << i][i] = dist[0][i];
//初始化
for(i = 1; i < 1 << n; i ++)
for(j = 0; j < n; j ++)
if (i & (1 << j))
for(k = 0; k < n; k ++)
if (! (i & (1 << k)))
f[i | (1 << k)][k] = min(f[i | (1 << k)][k], f[i][j] + dist[j][k]);
//状态转移
printf("%d", f[(1 << n) - 1][0]);
//输出答案
return 0;
}
- n更大的数据/应该/是用搜索+剪枝QAQ