贴一篇大牛博客:http://www.cnblogs.com/martinue/p/5490432.html
思路:因为题目中要求一个点只能经过两次,所以我们就需要一个数组来保存在每一个状态中每一位的数值是多少。
我们只需要判断你去的城市的到达次数<2就行了。
具体看代码解释:
#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <cctype>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define MOD 1e9+7
#define PI acos(-1)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 12;
int three[maxn], dig[60005][maxn];//three存放三的幂次,dig[i][j]状态i的第j位是数字几
int n, m, mp[maxn][maxn], dp[60005][maxn]; //dp[i][j]表示第i种状态当前在j点
void init() {
three[0] = 1;
for(int i = 1; i <= 10; i++) {
three[i] = three[i - 1] * 3;
}
for(int i = 0; i < three[10]; i++) {
int x = i;
for(int j = 0; j < 10; j++) {
dig[i][j] = x % 3;
x /= 3;
}
}
}
int main() {
init();
while(~scanf("%d%d", &n, &m)) {
memset(mp, 0x3f, sizeof(mp));
memset(dp, 0x3f, sizeof(dp));
for(int i = 1; i <= m; i++) {
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
u--;//--是因为题目中是[1.n]的范围,在状压中最好是[0,n-1]
v--;
mp[u][v] = mp[v][u] = min(mp[u][v], w);
}
for(int i = 0; i < n; i++) {
dp[three[i]][i] = 0;
}
int ans = INF;
for(int s = 0; s < three[n]; s++) {
int flag = 1;
for(int i = 0; i < n; i++) {//当前位置
if(dig[s][i] == 0) {//如果你当前所在城市没有访问过,那么你从这个城市去访问别的城市是非法的
flag = 0;
continue;
}
for(int j = 0; j < n; j++) {//要去的城市
if(dig[s][j] == 2) continue;//如果你要去的城市已经去过了两次,那么你就i不能在访问了
dp[s + three[j]][j] = min(dp[s + three[j]][j], dp[s][i] + mp[i][j]);
//dp更新
}
}
if(flag) {//如果在状态s下,每个城市都访问过了,那么就寻找最小值
for(int i = 0; i < n; i++) ans = min(ans, dp[s][i]);
}
}
if(ans != INF)printf("%d\n", ans);
else printf("-1\n");
}
return 0;
}