题意:有n个城市,m条路,[1,k]的城市有居民, [n-k+1, n]的城市有庇护所, 现在要修路, 使得每一座城市的居民都可以到达一个庇护所, 并且一个庇护所只能容纳一个城市的居民, 现在求所有城市的居民都能到达庇护所的最小花费。
题解:斯坦纳树跑出花费。 d[i][state] = cost, i代表的是第i个城市, state代表的是联通的状态, val代表的是花费。
先跑出所有的d[i][state]的花费。然后由于不需要是联通图, 再最后跑出每种符合的最小花费。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout); 4 #define LL long long 5 #define ULL unsigned LL 6 #define fi first 7 #define se second 8 #define pb push_back 9 #define lson l,m,rt<<1 10 #define rson m+1,r,rt<<1|1 11 #define max3(a,b,c) max(a,max(b,c)) 12 #define min3(a,b,c) min(a,min(b,c)) 13 typedef pair<int,int> pll; 14 const int inf = 0x3f3f3f3f; 15 const LL INF = 0x3f3f3f3f3f3f3f3f; 16 const LL mod = (int)1e9+7; 17 const int N = 55, M = 2005; 18 int head[N], nt[M], to[M], ct[M], tot; 19 int d[N][1<<10], s[N], vis[N][1<<10], dp[1<<10]; 20 int n, m, k, nn; 21 void init(){ 22 memset(head, -1, sizeof(head)); 23 memset(s, 0, sizeof(s)); 24 tot = 0; 25 } 26 inline void add(int u, int v, int w){ 27 to[tot] = v; 28 ct[tot] = w; 29 nt[tot] = head[u]; 30 head[u] = tot++; 31 } 32 void input(){ 33 int u, v, c; 34 for(int i = 1; i <= m; i++){ 35 scanf("%d%d%d", &u, &v, &c); 36 add(u, v, c); 37 add(v, u, c); 38 } 39 for(int i = 1; i <= n; i++) 40 for(int j = 0; j < nn; j++) d[i][j] = inf; 41 for(int i = 1; i <= k; i++){ 42 s[i] = 1<<(i-1); d[i][s[i]] = 0; 43 s[n-i+1] = 1<<(k+i-1), d[n-i+1][s[n-i+1]] = 0; 44 } 45 } 46 queue<int> q; 47 inline bool update(int x, int y, int w){ 48 if(d[x][y] <= w) return false; 49 d[x][y] = w; 50 return true; 51 } 52 void spfa(){ 53 int t, x, y; 54 while(!q.empty()){ 55 t = q.front(); 56 q.pop(); 57 x = t / 10000, y = t%10000; 58 vis[x][y] = 0; 59 for(int i = head[x]; ~i; i = nt[i]){ 60 if(update(to[i],y|s[to[i]],d[x][y]+ct[i]) && y == (y|s[to[i]]) && !vis[to[i]][y]){ 61 vis[to[i]][y] = 1; 62 q.push(to[i]*10000+y); 63 } 64 } 65 } 66 } 67 bool check(int x){ 68 int r = 0; 69 for(int i = 0;x;i++, x>>=1) 70 r += (x&1)*(i<k?1:-1); 71 return r==0; 72 } 73 void solve(){ 74 for(int i = 0; i < nn; i++){ 75 for(int j = 1; j <= n; j++){ 76 for(int k = (i-1)&i; k; k = (k-1)&i) 77 d[j][i] = min(d[j][i], d[j][k|s[j]]+d[j][s[j]|(i-k)]); 78 if(d[j][i] < inf) q.push(i+j*10000), vis[j][i] = 1; 79 } 80 spfa(); 81 } 82 for(int i = 0; i < nn; i++){ 83 dp[i] = inf; 84 for(int j = 1; j <= n; j++) dp[i] = min(dp[i], d[j][i]); 85 } 86 for(int i = 1; i < nn; i++){ 87 if(check(i)){ 88 for(int j = i&(i-1); j; j = (j-1)&i){ 89 if(check(j)) dp[i] = min(dp[i], dp[j]+dp[i-j]); 90 } 91 } 92 } 93 if(dp[nn-1]>=inf) puts("No solution"); 94 else printf("%d\n", dp[nn-1]); 95 } 96 int main(){ 97 int t, u, v, c; 98 scanf("%d", &t); 99 while(t--){ 100 init(); 101 scanf("%d%d%d", &n, &m, &k); 102 nn = 1<<(2*k); 103 input(); 104 solve(); 105 } 106 return 0; 107 }
原文地址:https://www.cnblogs.com/MingSD/p/9346151.html
时间: 2024-11-05 13:25:52