HDU 4085 Peach Blossom Spring

斯坦纳树。

最后可以是森林,在计算出每个联通状态的最小费用后,还需要进行一次$dp$。

#include<bits/stdc++.h>
using namespace std;

const int INF=0x7FFFFFFF;
int T,n,m,k;
vector<int>g[60];
int val[60][60],id[60],d[60][1200],dp[1200];
int f[60*10000];
queue<int>Q;

void spfa()
{
    while(!Q.empty())
    {
        int h = Q.front(); Q.pop(); f[h]=0;
        int x=h/10000,y=h%10000;
        for(int i=0;i<g[x].size();i++)
        {
            int to = g[x][i];

            if(to<2*k)
            {
                if(((1<<to)&y)==0)
                {
                    if(d[x][y]+val[x][to]<d[to][y|(1<<to)])
                        d[to][y|(1<<to)]=d[x][y]+val[x][to];
                }
            }

            else
            {
                if(d[x][y]+val[x][to]<d[to][y])
                {
                    d[to][y] = d[x][y]+val[x][to];
                    if(f[to*10000+y]==0)
                    {
                        f[to*10000+y]=1;
                        Q.push(to*10000+y);
                    }
                }
            }
        }
    }
}

bool check(int x)
{
    int sum1=0,sum2=0;
    for(int i=0;i<=k-1;i++) if(x&(1<<i)) sum1++;
    for(int i=k;i<=2*k-1;i++) if(x&(1<<i)) sum2++;
    if(sum1==sum2) return 1;
    return 0;
}

int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d%d",&n,&m,&k);

        for(int i=0;i<n;i++)
        {
            id[i]=i;
            g[i].clear();
        }

        id[k]=n-k; for(int i=k+1;i<=2*k-1;i++) id[i]=id[i-1]+1;
        id[n-k]=k; for(int i=n-k+1;i<=n-1;i++) id[i]=id[i-1]+1;

        for(int i=0;i<n;i++)
            for(int j=0;j<n;j++) val[i][j]=INF;
        memset(f,0,sizeof f);

        for(int i=1;i<=m;i++)
        {
            int a,b,c; scanf("%d%d%d",&a,&b,&c);
            a--; b--; a=id[a]; b=id[b];
            val[a][b]=min(val[a][b],c);
            val[b][a]=val[a][b];
            g[a].push_back(b);
            g[b].push_back(a);
        }

        int st = 1<<(2*k);

        for(int j=0;j<st;j++)
            for(int i=0;i<n;i++) d[i][j]=INF;

        for(int i=0;i<n;i++)
        {
            if(i<2*k) d[i][1<<i]=0;
            else d[i][0]=0;
        }

        for(int j=0;j<st;j++)
        {
            for(int i=0;i<n;i++)
            {
                if(i<2*k)
                {
                    if(((1<<i)&j)==0) continue;
                    for (int x = j; x; x = (x-1)&j)
                    {
                        int A=x ,B=j-A;
                        if(d[i][A|(1<<i)]!=INF&&d[i][B|(1<<i)]!=INF)
                            d[i][j] = min(d[i][j], d[i][A|(1<<i)]+d[i][B|(1<<i)]);
                    }
                }
                else
                {
                    for (int x = j; x; x = (x-1)&j)
                    {
                        int A=x ,B=j-A;
                        if(d[i][A]!=INF&&d[i][B]!=INF)
                            d[i][j] = min(d[i][j], d[i][A]+d[i][B]);
                    }
                }

                if(d[i][j]!=INF) Q.push(i*10000+j);
            }
            spfa();
        }

        for(int j=0;j<st;j++)
        {
            dp[j]=INF;
            for(int i=0;i<n;i++) dp[j]=min(dp[j],d[i][j]);
        }

        for(int j=0;j<st;j++)
        {
            for (int x = j; x; x = (x-1)&j)
            {
                int A=x ,B=j-A;
                if(check(A)&&check(B)&&dp[A]!=INF&&dp[B]!=INF)
                    dp[j]=min(dp[j],dp[A]+dp[B]);
            }
        }

        if(dp[st-1]!=INF) printf("%d\n",dp[st-1]);
        else printf("No solution\n");
    }
    return 0;
}

 

posted @ 2017-03-29 10:18  Fighting_Heart  阅读(199)  评论(0编辑  收藏  举报