(1)这道题最多可以走两次,所以有0, 1, 2三种状态,所以我们要用三进制
如果要用三进制,就要自己初始化两个数组, 一个是3的n次方,一个是三进制数的第几位的数字是什么
void init()
{three[0] = 1;REP(i, 1, 11)three[i] = three[i-1] * 3;REP(i, 0, three[10]){int t = i;REP(j, 0, 10){digit[i][j] = t % 3;t /= 3;if(t == 0) break;}}
}
同时这里不能用位运算,因为不是二进制。如果涉及到某一位加1,就加上就好了,不能用|
然后统计答案的时候比较麻烦,要枚举每一位是不是0
(2)凡是涉及到进制的,下标都从0开始。输入的时候记得要下标减减
(3)Tsp问题的基本套路是这样的(我用的是填表法)
dp数组全部初始化为最大值
起点初始化为0,即dp[1 << i][i] = 0
第一层循环枚举所有可能的状态S
第二层枚举当前点i,这里要求这个点已经经过
第二层枚举之前的点j,这里同样要求这个点已经经过
dp[state][i] = min(dp[state][i], dp[state^(1 << i)][j] + dist[j][i])
记住要去掉当前这个点
最后答案就是min(dp[(1 << n) - 1][i])
#include<cstdio>
#include<cstring>
#include<algorithm>
#define REP(i, a, b) for(int i = (a); i < (b); i++)
#define _for(i, a, b) for(int i = (a); i <= (b); i++)
using namespace std;const int MAXN = 15;
int dist[MAXN][MAXN], dp[60000][MAXN], n, m;
int three[MAXN], digit[60000][MAXN];void init()
{three[0] = 1;REP(i, 1, 11)three[i] = three[i-1] * 3;REP(i, 0, three[10]){int t = i;REP(j, 0, 10){digit[i][j] = t % 3;t /= 3;if(t == 0) break;}}
}int main()
{init();while(~scanf("%d%d", &n, &m)){memset(dist, 0x3f, sizeof(dist));while(m--){int u, v, w;scanf("%d%d%d", &u, &v, &w); u--; v--; //注意要-- dist[u][v] = dist[v][u] = min(dist[u][v], w);}int ans = 1e9;memset(dp, 0x3f, sizeof(dp)); //初始化不能忘 REP(i, 0, n) dp[three[i]][i] = 0;REP(S, 0, three[n]){bool ok = true;REP(i, 0, n){if(digit[S][i] == 0) { ok = false; continue; } //i要已经经过。 REP(j, 0, n) if(digit[S][j] >= 1) //j已经经过 dp[S][i] = min(dp[S][i], dp[S-three[i]][j] + dist[j][i]);} if(ok) REP(i, 0, n) ans = min(ans, dp[S][i]);}printf("%d\n", ans == 1e9 ? -1 : ans);}return 0;
}