1. 程式人生 > >Travelling (三進位制+狀壓dp)

Travelling (三進位制+狀壓dp)

題目連結

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 inline ll read(){
 5     int x=0,f=1;char ch=getchar();
 6     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
 7     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
 8     return
x*f; 9 } 10 11 /***********************************************************/ 12 13 int n, m; // n < = 10 14 const int maxn = 6e4+5; 15 int d[12][maxn]; 16 //用三進位制形式來表示狀態 17 int dist[15][15]; 18 //表示路徑 19 int t[12]; 20 int cnt, state[maxn]; 21 int temp; 22 23 //判斷S的三進位制是否沒有一個0 24 bool legal(int
S){ 25 bool ok = true; 26 for(int i = 0;i <= n-1;i++){ 27 if(S%3 == 0){ 28 ok = false; 29 break; 30 } 31 S /= 3; 32 } 33 return ok; 34 } 35 36 void init(){ 37 temp = 1; 38 for(int i = 0;i <= 10;i++){ 39 t[i] = temp;
40 temp *= 3; 41 } 42 } 43 44 //i點在集合S中是否出現了至少一次 45 inline bool in(int i, int S){ 46 for(int j = 0;j < i;j++) 47 S /= 3; 48 if(S%3) return true; 49 else return false; 50 } 51 52 int dp(int i, int S){ 53 if(d[i][S] >= 0) return d[i][S]; 54 int &ans = d[i][S]; 55 ans = 1e9; 56 int S1 = S - t[i]; 57 for(int j = 0;j < n;j++){ 58 if(j != i && in(j, S1) && dist[j][i] != -1) 59 ans = min(ans, dp(j, S1) + dist[j][i]); 60 } 61 return ans; 62 } 63 64 int main(){ 65 init(); 66 while(~scanf("%d %d", &n, &m)){ 67 int max_3 = 0; 68 for(int i = 0;i < n;i++) 69 max_3 += t[i]; 70 cnt = 0; 71 for(int S = max_3;S < t[n];S++){ 72 if(legal(S)) 73 state[cnt++] = S; 74 } 75 memset(dist, -1, sizeof(dist)); 76 for(int i = 0;i < m;i++){ 77 int a, b, c; 78 scanf("%d%d%d", &a, &b, &c); 79 a--;b--; 80 //更新長度 81 if(dist[a][b] == -1 || dist[a][b] > c) 82 dist[a][b] = dist[b][a] = c; 83 } 84 memset(d, -1, sizeof(d)); 85 for(int i = 0;i < n;i++) 86 d[i][t[i]] = 0; 87 88 int sum = dp(0, max_3); 89 for(int i = 0;i < n;i++){ 90 for(int j = 0;j < cnt;j++){ 91 sum = min(sum, dp(i, state[j])); 92 } 93 } 94 if(sum == 1e9) printf("-1\n"); 95 else printf("%d\n", sum); 96 } 97 return 0; 98 }