HDU 4756 Install Air Conditioning 块与块,非树边最短路

来源:互联网 发布:2016gdp 知乎 编辑:程序博客网 时间:2024/05/18 03:17

题意:给你一个n个点的坐标,之间两两相连,其中2~n-1形成的边中有一条边不能用,问你最小生成树的最大值。


想法:当对原图求最小生成树之后,记录这一棵树,当我们删除一条边之后,最小生成树就分成了A,B两个连通分量,则需要保存当删除这条边是A到B的最短距离。


小技巧:现在的问题就是:删除一边,求A到B的最短距离?

最笨的方法肯定太耗时间了,就是枚举每一条边然后跑spfa那么时间复杂度就是O(edges^3),但是通过树形dp,枚举每一个点那么时间复杂度O(n^2),又是因为edges=n^2。把枚举的点当成是root点,也就是规定有root的A到B一定是root->B中的点最短。dp[u][v]表示删除uv这条边两个连通块的最短距离。

还有一点要注意的是与root相连的点是不可以更新的,因为root->v是要删除的最小生成树的边,而要找的是除它以外的边。


#include<iostream>#include<cstring>#include<cstdio>#include<cmath>#define inf 0x7fffffffusing namespace std;int n,k;double map[1000+50][1000+50],dp[1000+50][1000+50];int used[1000+50][1000+50],pre[1000+50];double ans;struct node{int x,y;}dir[1000+50];struct nodee{int v,next;}e[2000+50];int head[1000+50],cnt;void add(int a,int b){e[cnt].v=b;e[cnt].next=head[a];head[a]=cnt++;}void Input(){scanf("%d%d",&n,&k);for(int i=1;i<=n;i++){scanf("%d%d",&dir[i].x,&dir[i].y);}}double Max(double a,double b){if(a>b) return a;else return b;}double Min(double a,double b){if(a<b) return a;else return b;}double dis(node a,node b){double k=sqrt((double)(a.x-b.x)*(double)(a.x-b.x)+(double)(a.y-b.y)*(double)(a.y-b.y));return k;}void build_map(){for(int i=1;i<=n;i++){for(int j=i;j<=n;j++){map[i][j]=map[j][i]=dis(dir[i],dir[j]);dp[i][j]=dp[j][i]=(double)inf;}}}void prime(){int vis[1000+5];double low[1000+5];for(int i=1;i<=n;i++){low[i]=map[1][i];pre[i]=1;vis[i]=0;}low[1]=0;vis[1]=1;pre[1]=-1;for(int i=2;i<=n;i++){double min=inf;int pos;for(int j=1;j<=n;j++){if(!vis[j]&&min>low[j]){min=low[j];pos=j;}}vis[pos]=1;ans+=low[pos];used[pre[pos]][pos]=used[pos][pre[pos]]=1;add(pre[pos],pos);add(pos,pre[pos]);for(int j=1;j<=n;j++){if(!vis[j]&&map[pos][j]<low[j]){low[j]=map[pos][j];pre[j]=pos;}}}}double dfs(int root,int u,int fa){double res=(double)inf;for(int i=head[u];i+1;i=e[i].next){int v=e[i].v;if(v==fa) continue;double tmp=dfs(root,v,u);dp[u][v]=dp[v][u]=Min(tmp,dp[u][v]);res=Min(res,tmp);}if(root!=fa){res=Min(map[root][u],res);}return res;}void treatment(){memset(used,0,sizeof(used));memset(head,-1,sizeof(head));cnt=0;ans=0;prime();double Ans=ans;for(int i=1;i<=n;i++){dfs(i,i,-1);}for(int i=2;i<n;i++){for(int j=i+1;j<=n;j++){if(used[i][j]){Ans=Max(Ans,ans+dp[i][j]-map[i][j]);}}}printf("%.2lf\n",Ans*k);}int main(){int t;scanf("%d",&t);while(t--){Input();build_map();treatment();}return 0;} 


0 0
原创粉丝点击