两个题次小生成树的扩展题。
先prim求出最小生成树,枚举删除每条树边后求分割成的两部分之间的最小连接费用,这一步用一个O(n^2)的n遍dfs求解。
不过HDU 4756这个题我被sqrt函数卡死,之前的写法HDU被卡爆栈,給sqrt传负数爆栈
//double tmp=(double)(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]); dis[i][j]=dis[j][i]=sqrt(tmp);
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define N 1010 #define INF 0x3f3f3f3f using namespace std; int n,k; int x[N],y[N]; double dis[N][N]; double d[N]; int vis[N]; bool mp[N][N]; double ans; struct Edge{ int v,next; }edge[N*2]; int head[N],cnt; double dp[N][N]; void init(){ memset(head,-1,sizeof(head)); cnt=0; } void addedge(int u,int v){ edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].next=head[v]; head[v]=cnt++; } void prim(){ for(int i=0;i<n;i++){ vis[i]=0; d[i]=dis[0][i]; } vis[0]=-1; ans=0; memset(mp,0,sizeof(mp)); for(int i=1;i<n;i++){ double Min=(double)INF; int node=-1; for(int j=0;j<n;j++){ if(vis[j]!=-1 && d[j]<Min){ node=j; Min=d[j]; } } ans+=Min; mp[vis[node]][node]=mp[node][vis[node]]=1; addedge(vis[node],node); vis[node]=-1; for(int j=0;j<n;j++){ if(vis[j]!=-1 && d[j]>dis[node][j]){ vis[j]=node; d[j]=dis[node][j]; } } } } double dfs(int cur,int u,int fa){ double res=(double)INF; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v==fa)continue; double tmp=dfs(cur,v,u); dp[u][v]=dp[v][u]=min(tmp,dp[u][v]); res=min(res,tmp); } if(fa!=cur){ res=min(res,dis[cur][u]); } return res; } int main(){ //freopen("a.txt","r",stdin); //freopen("b.txt","w",stdout); int t,T; scanf("%d",&T); for(t=1;t<=T;t++){ scanf("%d %d",&n,&k); for(int i=0;i<n;i++){ scanf("%d %d",&x[i],&y[i]); } for(int i=0;i<n;i++){ for(int j=i;j<n;j++){ double tmp=(double)(x[i]-x[j])*(double)(x[i]-x[j])+(double)(y[i]-y[j])*(double)(y[i]-y[j]); //double tmp=(double)(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]); dis[i][j]=dis[j][i]=sqrt(tmp); } } init(); prim(); for(int i=0;i<n;i++) for(int j=i;j<n;j++) dp[i][j]=dp[j][i]=(double)INF; for(int j=0;j<n;j++) dfs(j,j,-1); double ANS=ans; //这里一定要初始化为ans //printf("%lf\n",ans); for(int i=1;i<n;i++){ for(int j=i+1;j<n;j++){ if(mp[i][j]){ ANS=max(ANS,ans-dis[i][j]+dp[i][j]); } } } printf("%.2lf\n",ANS*k); } return 0; }
HDU 4126
#include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define N 3010 #define INF 0x3f3f3f3f typedef long long ll; using namespace std; int n,m; int dis[N][N]; int d[N]; int vis[N]; bool mp[N][N]; ll ans; struct Edge{ int v,next; }edge[N*2]; int head[N],cnt; int dp[N][N]; void init(){ memset(head,-1,sizeof(head)); cnt=0; } void addedge(int u,int v){ edge[cnt].v=v; edge[cnt].next=head[u]; head[u]=cnt++; edge[cnt].v=u; edge[cnt].next=head[v]; head[v]=cnt++; } void prim(){ for(int i=0;i<n;i++){ vis[i]=0; d[i]=dis[0][i]; } vis[0]=-1; ans=0; memset(mp,0,sizeof(mp)); for(int i=1;i<n;i++){ int Min=INF; int node=-1; for(int j=0;j<n;j++){ if(vis[j]!=-1 && d[j]<Min){ node=j; Min=d[j]; } } ans+=Min; mp[vis[node]][node]=mp[node][vis[node]]=1; addedge(vis[node],node); vis[node]=-1; for(int j=0;j<n;j++){ if(vis[j]!=-1 && d[j]>dis[node][j]){ vis[j]=node; d[j]=dis[node][j]; } } } } int dfs(int cur,int u,int fa){ int res=INF; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].v; if(v==fa)continue; int tmp=dfs(cur,v,u); dp[u][v]=dp[v][u]=min(tmp,dp[u][v]); res=min(res,tmp); } if(fa!=cur){ res=min(res,dis[cur][u]); } return res; } int main(){ //freopen("a.txt","r",stdin); //freopen("b.txt","w",stdout); int u,v,w; while(scanf("%d %d",&n,&m)){ if(n==0 && m==0)break; for(int i=0;i<n;i++) for(int j=0;j<n;j++) dis[i][j]=INF; for(int i=0;i<m;i++){ scanf("%d %d %d",&u,&v,&w); dis[u][v]=dis[v][u]=w; } init(); prim(); for(int i=0;i<n;i++) for(int j=i;j<n;j++) dp[i][j]=dp[j][i]=INF; for(int j=0;j<n;j++) dfs(j,j,-1); ll ANS=0; //printf("%lf\n",ans); int q; scanf("%d",&q); for(int i=0;i<q;i++){ scanf("%d %d %d",&u,&v,&w); if(!mp[u][v]) ANS+=ans; else ANS+=ans-dis[u][v]+min(w,dp[u][v]); } printf("%.4lf\n",(double)ANS/q); } return 0; }