思路:虚拟一个0号节点,将每个点建一条到0号节点的边,权值为挖井需要的价值。并要保证0号节点同另外n个寺庙一样被选择即可。
然后就是求斯坦纳树了。
#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<string>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Maxn 1310
#define Maxm 100010
#define LL __int64
#define Abs(x) ((x)>0?(x):(-x))
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
#define inf 0x3f3f3f3f
#define Mod 1000000007
using namespace std;
int dp[Maxn][<<],dis[Maxn][Maxn],vi[Maxn],head[Maxn],e,n,m,p;
struct Edge{
int u,v,val,next;
}edge[Maxn*];
void init()
{
memset(dis,,sizeof(dis));
memset(dp,,sizeof(dp));
memset(vi,,sizeof(vi));
memset(head,-,sizeof(head));
e=;
}
void add(int u,int v,int val)
{
edge[e].u=u,edge[e].v=v,edge[e].val=val,edge[e].next=head[u],head[u]=e++;
edge[e].u=v,edge[e].v=u,edge[e].val=val,edge[e].next=head[v],head[v]=e++;
}
void spfa()
{
int i,v,now,j;
for(i=;i<=n+m;i++){
queue<int> q;
dis[i][i]=;
q.push(i);
while(!q.empty()){
now=q.front();
q.pop();
vi[now]=;
for(j=head[now];j!=-;j=edge[j].next){
v=edge[j].v;
if(v==now) continue;
if(dis[i][v]>dis[i][now]+edge[j].val){
dis[i][v]=dis[i][now]+edge[j].val;
if(!vi[v]){
q.push(v);
vi[v]=;
}
}
}
}
}
}
int solve()
{
int i,j,k;
spfa();
int x=n+m;
for(i=;i<=n;i++){
for(j=;j<=x;j++){
dp[j][<<i]=dis[i][j];
}
}
int N=<<(n+);
N--;
for(i=;i<=N;i++){
if(!(i&(i-))) continue;
for(j=;j<=x;j++){
dp[j][i]=inf;
for(k=i;k;k=(k-)&i){
dp[j][i]=min(dp[j][i],dp[j][k]+dp[j][i-k]);
}
}
for(j=;j<=x;j++){
for(k=;k<=x;k++){
dp[j][i]=min(dp[j][i],dp[k][i]+dis[k][j]);
}
}
}
return dp[][N];
}
int main()
{
int i,j,u,v,val;
while(scanf("%d%d%d",&n,&m,&p)!=EOF){
init();
for(i=;i<=n+m;i++){
scanf("%d",&val);
add(,i,val);
}
for(i=;i<=p;i++){
scanf("%d%d%d",&u,&v,&val);
add(u,v,val);
}
printf("%d\n",solve());
}
return ;
}