1. 程式人生 > >MST(prim)+樹形dp-hdu-4756-Install Air Conditioning

MST(prim)+樹形dp-hdu-4756-Install Air Conditioning

題目連結:

題目意思:

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;
}