2 1 1 2 100 3 2 1 2 40 2 3 50 3 3 1 2 3 1 3 4 2 3 10
100 90 7
题意:要走完所有的城市,每条边有一个代价,求走完所有的城市的最小代价,起初没看到每个城市最多可走两边。
思路:用二进制的状态压缩果然wa了,用三进制的状态压缩,先把进制表打好,然后用一个二维的数组表示出这个数每位在三进制下的状态,状态转移。
#include<iostream> #include<cstdio> #include<algorithm> #include<map> #include<cstring> #include<map> #include<set> #include<queue> #include<stack> using namespace std; const double eps = 1e-10; const int inf = 0x3f3f3f3f, N = 6e4; typedef long long ll; int dp[N][12], Map[12][12], n, m, three[12], vis[N][12]; 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 temp = i; for(int j = 1; j<=10; j++) { vis[i][j] = temp % 3; temp /= 3; } } } int main() { init(); while(~scanf("%d%d", &n, &m)) { memset(Map, 0x3f, sizeof(Map)); int u, v, w; while(m--) { scanf("%d%d%d", &u, &v, &w); Map[u][v] = Map[v][u] = min(w, Map[u][v]); } memset(dp, 0x3f, sizeof(dp)); int num = three[n] - 1; for(int i = 1; i<=n; i++) dp[three[i-1]][i] = 0; int ans = inf; for(int i = 1; i<=num; i++) { for(int j = 1; j<=n; j++) { if(dp[i][j] == inf) continue; for(int k = 1; k<=n; k++) { if(vis[i][k]>=2 || Map[j][k] == inf || j == k) continue; dp[i + three[k-1]][k] = min(dp[i + three[k-1]][k], dp[i][j] + Map[j][k]); } } } for(int i = 1; i<=num; i++) { int ok = 1; for(int j = 1; j<=n; j++) if(!vis[i][j]) { ok = 0; break; } if(ok) for(int j = 1; j<=n; j++) ans = min(dp[i][j], ans); } if(ans != inf) cout<<ans<<endl; else cout<<-1<<endl; } return 0; }