MST(prim)+樹形dp-hdu-4756-Install Air Conditioning
阿新 • • 發佈:2019-02-02
題目連結:
題目意思:
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; }