zoukankan      html  css  js  c++  java
  • MST(prim)+树形dp-hdu-4756-Install Air Conditioning

    题目链接:

    http://acm.hdu.edu.cn/showproblem.php?pid=4756

    题目意思:

    n-1个宿舍,1个供电站,n个位置每两个位置都有边相连,其中有一条边不能连,求n个位置连通的最小花费的最大值。

    解题思路:

    和这道题hdu-4126差不多,不过这题不能去掉与供电站相连的边。不同的是这题是一个完全图,求MST时,用kruscal算法的时间复杂度为elge很高会超时,用prim算法复杂度为n^2,所以选用prim算法。

    PS:

    double类型的不能用memset,置最大,wa了一个多小时。

    代码:

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    #include<cstdlib>
    #include<string>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<map>
    #include<set>
    #include<stack>
    #include<list>
    #include<queue>
    #include<ctime>
    #define eps 1e-6
    #define INF 0x3f3f3f3f
    #define PI acos(-1.0)
    #define ll __int64
    #define lson l,m,(rt<<1)
    #define rson m+1,r,(rt<<1)|1
    #pragma comment(linker, "/STACK:1024000000,1024000000")
    using namespace std;
    
    #define Maxn 1300
    
    struct Po
    {
        double x,y;
    }pp[Maxn];
    
    double dis[Maxn][Maxn]; //原始距离
    bool hav[Maxn][Maxn],vis[Maxn]; //是否为最小生成树上的边
    int pre[Maxn],;
    double dp[Maxn][Maxn];//dp[i][j]表示<i,j>为最小生成树上的边,且去掉该边后,包括点i的连通块中的点集A到包括点j的连通块点集B的最小距离。
    int n,m,cnt;
    double sum,ans,dd[Maxn];
    
    
    
    struct EE //构建最小生成树
    {
        int v;
        struct EE * next;
    }ee[Maxn<<1],*head[Maxn<<1];
    
    void add(int a,int b)
    {
        ++cnt;
        ee[cnt].v=b;
        ee[cnt].next=head[a];
        head[a]=&ee[cnt];
    }
    void prim()
    {
        cnt=0,sum=0;
        memset(vis,false,sizeof(vis));
        dd[0]=0;
        pre[0]=0;
        vis[0]=true;
        for(int i=1;i<n;i++)
        {
            dd[i]=dis[0][i];
            pre[i]=0;
        }
        for(int i=1;i<n;i++) //n-1条边
        {
            double mi=INF;
            int re;
    
            for(int j=0;j<n;j++)
            {
                if(!vis[j]&&dd[j]<mi)
                {
                    mi=dd[j];
                    re=j;
                }
            }
            vis[re]=true;
            sum+=mi;
            add(pre[re],re);
            add(re,pre[re]);
    
            for(int i=0;i<n;i++)
            {
                if(!vis[i]&&dis[re][i]<dd[i])
                {
                    dd[i]=dis[re][i];
                    pre[i]=re; //更新到集合的距离
                }
            }
        }
    
    }
    
    double dfs(int ro,int fa,int cur,int dep) //表示以cur作为当前子树根中所有子树节点到总根ro的最短距离
    {
        struct EE * p=head[cur];
        double mi=INF;
    
        if(dep!=1) //不为树根的儿子
            mi=dis[cur][ro];
        while(p)
        {
            int v=p->v;
            if(v!=fa)
            {
                //printf(":%d
    ",v);
                //system("pause");
                double tt=dfs(ro,cur,v,dep+1);
                mi=min(mi,tt);
                dp[cur][v]=dp[v][cur]=min(dp[v][cur],tt);//更新当前边
    
            }
            p=p->next;
        }
        return mi;
    
    }
    double Dis(int i,int j)
    {
        return sqrt(pow(pp[i].x-pp[j].x,2.0)+pow(pp[i].y-pp[j].y,2.0));
    }
    void dfs2(int cur,int fa)
    {
        struct EE * p=head[cur];
    
        while(p)
        {
            int v=p->v;
            if(v!=fa)
            {
                if(fa)
                    ans=max(ans,sum-dis[cur][v]+dp[cur][v]);
                dfs2(v,cur);
            }
            p=p->next;
        }
    }
    int main()
    {
       // printf("%d
    ",INF);
        double co;
        int tt;
        scanf("%d",&tt);
        while(tt--)
        {
            scanf("%d%lf",&n,&co);
            for(int i=0;i<n;i++)
                scanf("%lf%lf",&pp[i].x,&pp[i].y);
    
            for(int i=0;i<n;i++)
            {
                dis[i][i]=0;
                for(int j=i+1;j<n;j++)
                {
                    dis[i][j]=dis[j][i]=Dis(i,j);
                    //edge[nn].a=i,edge[nn].b=j,edge[nn].c=dis[i][j];
                }
            }
            //printf("%d %d
    ",nn,m);
            memset(hav,false,sizeof(hav));
            memset(head,NULL,sizeof(head));
            prim();
            for(int i=0;i<n;i++)
                for(int j=i+1;j<n;j++)
                    dp[i][j]=dp[j][i]=INF;
            for(int i=0;i<n;i++)  //以每个点最为树根,对每条边更新n次
            {
                dfs(i,i,i,0);
    //            for(int i=0;i<n;i++)
    //                for(int j=i+1;j<n;j++)
    //                {
    //                    printf("i:%d j:%d %lf
    ",i,j,dp[i][j]);
    //                }
                //system("pause");
            }
    
            ans=sum;
            //printf("%lf
    ",sum);
    //        for(int i=1;i<n;i++)
    //            for(int j=i+1;j<n;j++)
    //                if(hav[i][j])
    //                    ans=max(ans,sum-dis[i][j]+dp[i][j]);
            dfs2(0,0);
            printf("%.2f
    ",ans*co);
        }
       return 0;
    }
    



  • 相关阅读:
    [转] jQuery 操作 JSON 数据
    [转] 8张图学习javascript
    HTML文档类型声明的坑...
    Android 应用内HttpClient 与 WebView 共享 Cookie
    李嘉诚无锡演讲
    keytool 生成 Android SSL 使用的 BKS
    LeetCode-344-反转字符串
    LeetCode-342-4的幂
    LeetCode-338-比特位计数
    LeetCode-326-3的幂
  • 原文地址:https://www.cnblogs.com/james1207/p/3343501.html
Copyright © 2011-2022 走看看