hdu 3311 斯坦纳树

思路:虚拟一个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][1<<7],dis[Maxn][Maxn],vi[Maxn],head[Maxn],e,n,m,p;
struct Edge{
    int u,v,val,next;
}edge[Maxn*10];
void init()
{
    memset(dis,38,sizeof(dis));
    memset(dp,38,sizeof(dp));
    memset(vi,0,sizeof(vi));
    memset(head,-1,sizeof(head));
    e=0;
}
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=0;i<=n+m;i++){
        queue<int> q;
        dis[i][i]=0;
        q.push(i);
        while(!q.empty()){
            now=q.front();
            q.pop();
            vi[now]=0;
            for(j=head[now];j!=-1;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]=1;
                    }
                }
            }
        }
    }
}
int solve()
{
    int i,j,k;
    spfa();
    int x=n+m;
    for(i=0;i<=n;i++){
        for(j=0;j<=x;j++){
            dp[j][1<<i]=dis[i][j];
        }
    }
    int N=1<<(n+1);
    N--;
    for(i=1;i<=N;i++){
        if(!(i&(i-1))) continue;
        for(j=0;j<=x;j++){
            dp[j][i]=inf;
            for(k=i;k;k=(k-1)&i){
                dp[j][i]=min(dp[j][i],dp[j][k]+dp[j][i-k]);
            }
        }
        for(j=0;j<=x;j++){
            for(k=0;k<=x;k++){
                dp[j][i]=min(dp[j][i],dp[k][i]+dis[k][j]);
            }
        }
    }
    return dp[0][N];
}
int main()
{
    int i,j,u,v,val;
    while(scanf("%d%d%d",&n,&m,&p)!=EOF){
        init();
        for(i=1;i<=n+m;i++){
            scanf("%d",&val);
            add(0,i,val);
        }
        for(i=1;i<=p;i++){
            scanf("%d%d%d",&u,&v,&val);
            add(u,v,val);
        }
        printf("%d
",solve());
    }
    return 0;
}
原文地址:https://www.cnblogs.com/wangfang20/p/3287324.html