HDU 3311 Dig The Wells(斯坦纳树)

【题目链接】

    http://acm.hdu.edu.cn/showproblem.php?pid=3311

【题意】

    给定k座庙,n个其他点,m条边,点权代表挖井费用,边权代表连边费用,问使得k座庙里的所有和尚都能吃到水的最小费用。

【思路】

    首先一个相连的块里只要有口井就能保证块里的和尚有水。所以这个题目标并不是要让k个点连通,但我们可以转化一下。

    在原图的基础上我们添加0号结点,由0号结点向所有的点连边为该点的点权,代表挖井的费用,从而保证每个块里都有井,则问题转化为求以0为根包含k个点的斯坦纳树。

  模板可以上了。

    奇技淫巧系列。。。

【代码】

 1 #include<set>
 2 #include<cmath>
 3 #include<queue>
 4 #include<vector>
 5 #include<cstdio>
 6 #include<cstring>
 7 #include<iostream>
 8 #include<algorithm>
 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++)
11 using namespace std;
12 
13 typedef long long ll;
14 const int N = 1e3+10;
15 const int M = 2e4+10;
16 const int inf = 0xf0f0f0f;
17 const int P = 10;
18 
19 ll read() {
20     char c=getchar();
21     ll f=1,x=0;
22     while(!isdigit(c)) {
23         if(c=='-') f=-1; c=getchar();
24     }
25     while(isdigit(c))
26         x=x*10+c-'0',c=getchar();
27     return x*f;
28 }
29 struct Edge { int v,w,nxt;
30 }e[M];
31 int en=1,front[N];
32 void adde(int u,int v,int w) 
33 {
34     e[++en]=(Edge){v,w,front[u]}; front[u]=en;
35 }
36 
37 int n,m,K;
38 int f[1<<P][N];
39 queue<int> q; int inq[N];
40 
41 void spfa(int* dis) 
42 {
43     while(!q.empty()) {
44         int u=q.front(); q.pop();
45         inq[u]=0;
46         trav(u,i) {
47             int v=e[i].v;
48             if(dis[v]>dis[u]+e[i].w) {
49                 dis[v]=dis[u]+e[i].w;
50                 if(!inq[v])
51                     inq[v]=1,q.push(v);
52             }
53         }
54     }
55 }
56 
57 int main()
58 {
59     while(scanf("%d%d%d",&K,&n,&m)==3) {
60         en=1;
61         memset(front,0,sizeof(front));
62         int rt=0;
63         n+=K;
64         FOR(i,1,n) {
65             int w=read();
66             adde(rt,i,w),adde(i,rt,w);
67         }
68         FOR(i,1,m) {
69             int u=read(),v=read(),w=read();
70             adde(u,v,w),adde(v,u,w);
71         }
72         memset(f,0xf,sizeof(f));
73         FOR(i,0,K) f[1<<i][i]=0;
74         int all=1<<(K+1);
75         FOR(st,1,all-1) {
76             FOR(i,0,n) {
77                 for(int s=st&(st-1);s;s=(s-1)&st)
78                     f[st][i]=min(f[st][i],f[s][i]+f[st^s][i]);
79                 if(f[st][i]!=inf) q.push(i),inq[i]=1;
80             }
81             spfa(f[st]);
82         }
83         printf("%d
",f[all-1][rt]);
84     }
85     return 0;
86 }
原文地址:https://www.cnblogs.com/lidaxin/p/5301747.html