zoukankan      html  css  js  c++  java
  • hdu 4085 斯坦纳树

    思路:

    这里必须要选择的点是2*k个,首先就是求一边斯坦纳树,然后做一次动态规划出每个状态下的最小值。

    #include<map>
    #include<set>
    #include<cmath>
    #include<queue>
    #include<cstdio>
    #include<vector>
    #include<string>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define Maxn 210
    #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<<13],dis[Maxn][Maxn],n,m,K,ans[1<<13];
    void init()
    {
        memset(dp,63,sizeof(dp));
        memset(dis,63,sizeof(dis));
        memset(ans,63,sizeof(ans));
    }
    void floyd()
    {
        int i,j,k;
        for(k=1;k<=n;k++){
            dis[k][k]=0;
            for(i=1;i<=n;i++){
                for(j=1;j<=n;j++){
                    dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
                }
            }
        }
    }
    bool Ok(int s)
    {
        int res=0;
        for(int i=0;s;i++,s>>=1)
            res+=(s&1)*(i<K?1:-1);
        return (res==0?true:false);
    }
    void solve()
    {
        int i,j,k;
        int N=1<<(2*K);
        N--;
        for(i=0;i<K;i++){
            for(j=1;j<=n;j++){
                dp[j][1<<i]=dis[i+1][j];
                dp[j][1<<(K+i)]=dis[n-K+i+1][j];
            }
        }
        for(i=1;i<=N;i++){
            if((i&(i-1))==0) continue;
            for(j=1;j<=n;j++){
                dp[j][i]=inf;
                for(k=(i-1)&i;k;k=(k-1)&i){
                    dp[j][i]=min(dp[j][i],dp[j][k]+dp[j][i-k]);
    
                }
            }
            for(j=1;j<=n;j++){
                for(k=1;k<=n;k++){
                    dp[j][i]=min(dp[j][i],dp[k][i]+dis[j][k]);
                }
            }
        }
        for(i=1;i<=N;i++){
            ans[i]=inf;
            for(j=1;j<=n;j++) ans[i]=min(ans[i],dp[j][i]);
        }
        for(i=0;i<=N;i++){
            if(Ok(i)){
                for(j=(i-1)&i;j;j=(j-1)&i){
                    if(Ok(j)){
                        ans[i]=min(ans[i],ans[j]+ans[i-j]);
                    }
                }
            }
        }
        if(ans[N]>=inf)
            printf("No solution
    ");
        else
            printf("%d
    ",ans[N]);
    }
    int main()
    {
        int i,j,u,v,val,t;
        scanf("%d",&t);
        while(t--){
            scanf("%d%d%d",&n,&m,&K);
            init();
            for(i=1;i<=m;i++){
                scanf("%d%d%d",&u,&v,&val);
                dis[u][v]=dis[v][u]=min(dis[u][v],val);
            }
            floyd();
            solve();
        }
        return 0;
    }
  • 相关阅读:
    初涉数组
    声明
    简述java程序中的main方法
    概述java语言
    1.3 linux基础(三)
    linux基础之-screen命令
    1.2 linux基础(二)
    1.1 Linux基础(一)
    实验7-1-13 装箱问题
    实验7-1-12 组个最小数
  • 原文地址:https://www.cnblogs.com/wangfang20/p/3287608.html
Copyright © 2011-2022 走看看