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\n",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\n",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\n",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\n",i,j,dp[i][j]);

//                }

            //system("pause");

        }



        ans=sum;

        //printf("%lf\n",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\n",ans*co);

    }

   return 0;

}


 


 

你可能感兴趣的:(Condition)