hdu 4085 Peach Blossom Spring

Peach Blossom Spring

题意:有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

hdu 4085 Peach Blossom Spring的相关文章

HDU 4085 Peach Blossom Spring 记忆化搜索枚举子集 斯坦纳树

题目链接:点击打开链接 题意: 第一行输入n个点 m条可修建的无向边 k个人 下面给出修建的边和修建该边的花费. 开始时k个人在1-k的每个点上(一个点各一人) 目标:从m条给定边中修建部分边使得花费和最小 让k个人移动到 [n-k+1, n] 后面的k个点上(每个点放一个人). 思路: 首先就是一道斯坦纳树,还是先求一个dp数组(求解方法:点击打开链接) dp[i][j] 表示以i为根 ,j为8个点中是否在 i 的子树里 时的最小花费. 现在的问题就是如何求答案. 因为一个人到他的目标点这条路

HDU 4085 Peach Blossom Spring 斯坦纳树 状态压缩DP+SPFA

状态压缩dp+spfa解斯坦纳树 枚举子树的形态 dp[i][j] = min(dp[i][j], dp[i][k]+dp[i][l]) 其中k和l是对j的一个划分 按照边进行松弛 dp[i][j] = min(dp[i][j], dp[i'][j]+w[i][j])其中i和i'之间有边相连 #include <cstdio> #include <cstring> #include <queue> using namespace std; const int maxn

HDU 4081 Peach Blossom Spring (最小生成树+dfs)

题意:给定一个 n 个点和相应的权值,要求你用 n-1 条边连接起来,其中一条边是魔法边,不用任何费用,其他的边是长度,求该魔法边的两端的权值与其他边费用的尽量大. 析:先求出最小生成树,然后再枚举每一条边,求出最大值,任意两点之间的距离可以通过预处理来解决,最小生成树时,要用prime算法,要不然可能会超时. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio> #i

HDU4085 Peach Blossom Spring

Tao Yuanming(365-427) was a Chinese poet of Eastern Jin dynasty. One of his most famous works is "Peach Blossom Spring", which is a fable about a chance discovery of an ethereal village where the people lead an ideal existence in harmony with na

HDU 4085 斯坦纳树模板题

Dig The Wells Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 971    Accepted Submission(s): 416 Problem Description You may all know the famous story "Three monks". Recently they find som

HDU 4085 斯坦纳树

题目大意: 给定无向图,让前k个点都能到达后k个点(保护地)中的一个,而且前k个点每个需要占据后k个中的一个,相互不冲突 找到实现这个条件达到的选择边的最小总权值 这里很容易看出,最后选到的边不保证整个图是联通的 我们只要计算出每一个连通的最小情况,最后跑一遍dfs就能计算出答案了 那么用dp[i][j]表示 i 点为根得到联通状态为 j 的情况需要选到的边的最小总权值 这个用斯坦纳树的思想就可以做到的 对于每一个状态,都用spfa跑一遍得到最优解 dp[i][j] = min(dp[i][j]

HDU 4085 Steiner树模板称号

Dig The Wells Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 971    Accepted Submission(s): 416 Problem Description You may all know the famous story "Three monks". Recently they find som

HDU 4085 斯坦纳树+DP

https://cn.vjudge.net/problem/HDU-4085 给你n,m,k ,分别表示有n个点,m条边,每条边有一个权值,表示修复这条边需要的代价 从前k个点中任取一个使其和后k个点中的某一个点,通过边连接,并且必须是一一对应,问最小的代价是多少. 原文地址:https://www.cnblogs.com/Aragaki/p/10989578.html

图论 500题——主要为hdu/poj/zoj

转自——http://blog.csdn.net/qwe20060514/article/details/8112550 =============================以下是最小生成树+并查集======================================[HDU]1213   How Many Tables   基础并查集★1272   小希的迷宫   基础并查集★1325&&poj1308  Is It A Tree?   基础并查集★1856   More i