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\n",solve());

    }

    return 0;

}

 

你可能感兴趣的:(HDU)