hdu 4756 MST+树形dp ****
题意:给你n(n = 1000)个二维点,第一个点是power plant,还有n - 1个点是dormitories。然后现在知道有一条寝室到寝室的边是不能连的,但是我们不知道是哪条边,问这种情况下,最小生成树的最大值。
好题,毕竟做了一下午,注意dis要double转换
dfs求的是从cur点出发到以u为根的树的最小距离,可以是树根,也可以是树的子节点
枚举的边一定是在最小生成树上的,这个边被删除后,我们需要重新建立一条边来替代它,因此需要dfs来求
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define MOD 1000000007 10 const int INF=0x3f3f3f3f; 11 const double eps=1e-5; 12 typedef long long ll; 13 #define cl(a) memset(a,0,sizeof(a)) 14 #define ts printf("*****\n"); 15 const int MAXN=1005; 16 int n,m,tt; 17 /* 18 * Kruskal算法求MST 19 */ 20 const int MAXM=10000000;//最大边数 21 int tol;//边数,加边前赋值为0 22 struct Edge 23 { 24 int to,next; 25 }edge[MAXM]; 26 int head[MAXN],tot; 27 void init() 28 { 29 tot = 0; 30 memset(head,-1,sizeof(head)); 31 } 32 void addedge(int u,int v) 33 { 34 edge[tot].to = v; edge[tot].next = head[u]; 35 head[u] = tot++; 36 } 37 bool mp[MAXN][MAXN]; 38 double dp[MAXN][MAXN]; 39 /* 40 * Prim求MST 41 * 耗费矩阵cost[][],标号从0开始,0~n-1 42 * 返回最小生成树的权值,返回-1表示原图不连通 43 */ 44 int vis[MAXN]; 45 double lowc[MAXN]; 46 double Prim(double cost[][MAXN],int n)//点是0~n-1 47 { 48 double ans=0; 49 memset(vis,false,sizeof(vis)); 50 vis[0]=-1; 51 int last[MAXN]; 52 last[0]=0; 53 for(int i=1;i<n;i++)lowc[i]=cost[0][i]; 54 for(int i=1;i<n;i++) 55 { 56 double minc=INF; 57 int p=-1; 58 for(int j=0;j<n;j++) 59 if(vis[j]!=-1&&minc>lowc[j]) 60 { 61 minc=lowc[j]; 62 p=j; 63 } 64 if(minc==INF)return -1;//原图不连通 65 mp[vis[p]][p]=mp[p][vis[p]]=1; 66 addedge(vis[p],p); 67 addedge(p,vis[p]); 68 ans+=minc; 69 vis[p]=-1; 70 for(int j=0;j<n;j++) 71 if(vis[j]!=-1&&lowc[j]>cost[p][j]) 72 { 73 vis[j]=p; 74 lowc[j]=cost[p][j]; 75 } 76 } 77 return ans; 78 } 79 int x[MAXN],y[MAXN]; 80 double dist[MAXN][MAXN]; 81 double dis(int i,int j) 82 { 83 return sqrt((double)(x[i]-x[j])*(double)(x[i]-x[j])+(double)(y[i]-y[j])*(double)(y[i]-y[j])); 84 } 85 double dfs(int cur,int u,int fa){ 86 double res=(double)INF; 87 for(int i=head[u];i!=-1;i=edge[i].next){ 88 int v=edge[i].to; 89 if(v==fa)continue; 90 double tmp=dfs(cur,v,u); 91 dp[u][v]=dp[v][u]=min(tmp,dp[u][v]); 92 res=min(res,tmp); 93 } 94 if(fa!=cur){ 95 res=min(res,dist[cur][u]); 96 } 97 return res; 98 } 99 int main() 100 { 101 int i,j,k,ca=1; 102 #ifndef ONLINE_JUDGE 103 freopen("1.in","r",stdin); 104 #endif 105 scanf("%d",&tt); 106 int val; 107 while(tt--) 108 { 109 init(); 110 tol=0; 111 scanf("%d%d",&n,&val); 112 cl(dist); 113 for(i=0;i<n;i++) 114 { 115 scanf("%d%d",x+i,y+i); 116 } 117 for(i=0;i<n;i++) 118 { 119 for(j=0;j<n;j++) 120 { 121 dist[i][j]=dist[j][i]=dis(i,j); 122 } 123 } 124 cl(mp); 125 double sumw=Prim(dist,n); 126 double Max=sumw; 127 for(int i=0;i<n;i++) 128 for(int j=i;j<n;j++) 129 dp[i][j]=dp[j][i]=(double)INF; 130 for(i=0;i<n;i++) 131 { 132 dfs(i,i,-1); 133 } 134 for(i=1;i<n;i++) //枚举每条边 135 { 136 for(j=i+1;j<n;j++) 137 { 138 if(mp[i][j]) Max=max(Max,sumw-dist[i][j]+dp[i][j]); 139 } 140 } 141 printf("%.2lf\n",Max*val); 142 } 143 }