Dig The Wells

You may all know the famous story “Three monks”. Recently they find some places around their temples can been used to dig some wells. It will help them save a lot of time. But to dig the well or build the road to transport the water will cost money. They do not want to cost too much money. Now they want you to find a cheapest plan.

Input

There are several test cases.
Each test case will starts with three numbers n , m, and p in one line, n stands for the number of monks and m stands for the number of places that can been used, p stands for the number of roads between these places. The places the monks stay is signed from 1 to n then the other m places are signed as n + 1 to n + m. (1 <= n <= 5, 0 <= m <= 1000, 0 <=p <= 5000)
Then n + m numbers followed which stands for the value of digging a well in the ith place.
Then p lines followed. Each line will contains three numbers a, b, and c. means build a road between a and b will cost c.

Output

For each case, output the minimum result you can get in one line.

Sample Input

3 1 3
1 2 3 4
1 4 2
2 4 2
3 4 4 
4 1 4
5 5 5 5 1
1 5 1
2 5 1
3 5 1
4 5 1

Sample Output

6
5

 

 

 

 

 

题解

小清新斯坦纳树板题

记得做最小生成树的时候有一个类似的题

直接建一个虚点,把它视作唯一的水源,其他点向它连边,把打井的费用作为边权

这样,我们就只需要把寺庙和水源全部连通即可

直接斯坦纳树

(之前TLE了好久,结果发现自己的边数开小了。。。)

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define N 1015
#define M 7005
const int INF=0x3f3f3f3f;
int fir[N],to[2*M],nxt[2*M],cd[2*M],cnt;
int f[N][1<<6];
queue<int> q;bool inq[N];
void adde(int a,int b,int c)
{
	to[++cnt]=b;nxt[cnt]=fir[a];fir[a]=cnt;cd[cnt]=c;
	to[++cnt]=a;nxt[cnt]=fir[b];fir[b]=cnt;cd[cnt]=c;
}
int main()
{
	int k,n,m,i,s,t,u,v,w,p;
	while(scanf("%d%d%d",&k,&n,&m)==3){
		memset(fir,0,sizeof(fir));cnt=0;
		memset(f,0x3f,sizeof(f));
		n=n+k;
		for(i=1;i<=n;i++){scanf("%d",&w);adde(0,i,w);}
		for(i=1;i<=m;i++){scanf("%d%d%d",&u,&v,&w);adde(u,v,w);}
		for(i=0;i<=n;i++)f[i][0]=0;
		for(i=0;i<=k;i++)f[i][1<<i]=0;
		int all=(1<<(k+1))-1;
		for(s=1;s<=all;s++){
			for(i=0;i<=n;i++)
				for(t=(s-1)&s;t;t=(t-1)&s)
					f[i][s]=min(f[i][s],f[i][t]+f[i][s^t]);
			for(i=0;i<=n;i++)if(f[i][s]<INF)q.push(i),inq[i]=1;
			while(!q.empty()){
				u=q.front();q.pop();inq[u]=0;
				for(p=fir[u];p;p=nxt[p]){
					v=to[p];
					if(f[u][s]+cd[p]<f[v][s]){
						f[v][s]=f[u][s]+cd[p];
						if(!inq[v])q.push(v),inq[v]=1;
					}
				}
			}
		}
		int ans=INF;
		for(i=0;i<=n;i++)ans=min(ans,f[i][all]);
		printf("%d\n",ans);
	}
}