南京网络赛的题目
题意:有一条边不能用,但不知道是哪条,问最坏情况的最小生成树的大小。
思路:最容易想到的做法就是求最小生成树,然后枚举的删去最小生成树上的边,再求最小生成树,取最大值。n^3, 超时
那么可以用求次小生成树的思想,求出每条最小生成树上的边的最小替代边。这个可以用树形dp的思想n^2解决。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int maxn=1e3+9;
const double inf=1e11;
double x[maxn],y[maxn];
int from[maxn];
int n,m;
double e[maxn][maxn],g[maxn][maxn];
bool visit[maxn];
double key[maxn],dist[maxn];
int head[maxn],lon;
struct
{
int to,next,from;
}edge[maxn<<1];
inline double min(double a,double b)
{
if(a<b) return a;
return b;
}
inline double max(double a,double b)
{
if(a>b) return a;
return b;
}
void edgeini()
{
memset(head,-1,sizeof(head));
lon=0;
}
void edgemake(int from,int to)
{
edge[++lon].to=to;
edge[lon].next=head[from];
edge[lon].from=from;
head[from]=lon;
}
inline double cal(int t,int s)
{
double a=(x[t]-x[s])*(x[t]-x[s]);
double b=(y[t]-y[s])*(y[t]-y[s]);
return sqrt(a+b);
}
double prim()
{
memset(visit,0,sizeof(visit));
visit[1]=1;
for(int i=1;i<=n;i++)
{
key[i]=e[1][i];
from[i]=1;
}
double ans=0;
for(int k=2,u;k<=n;k++)
{
double now=inf;
for(int i=1;i<=n;i++)
if(key[i]<now&&!visit[i])
{
u=i;
now=key[i];
}
ans+=key[u];
visit[u]=1;
edgemake(u,from[u]);
edgemake(from[u],u);
for(int i=1;i<=n;i++)
if(!visit[i]&&key[i]>e[u][i])
{
key[i]=e[u][i];
from[i]=u;
}
}
return ans;
}
double dfs(int now,int from)
{
double mmin=dist[now];
for(int k=head[now],u;k!=-1;k=edge[k].next)
{
u=edge[k].to;
if(u==from) continue;
mmin=min(dfs(u,now),mmin);
}
g[now][from]=g[from][now]=min(g[from][now],mmin);
return mmin;
}
int main()
{
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while(T--)
{
edgeini();
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%lf %lf",&x[i],&y[i]);
for(int i=1;i<=n;i++)
for(int j=i;j<=n;j++)
e[i][j]=e[j][i]=cal(i,j);
double ans=prim();
for(int i=1;i<=lon;i++)
g[edge[i].from][edge[i].to]=inf;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
dist[j]=e[i][j];
for(int k=head[i];k!=-1;k=edge[k].next)
dist[edge[k].to]=inf;
dfs(i,0);
}
double ret=ans;
for(int i=1;i<=lon;i++)
if(edge[i].from!=1&&edge[i].to!=1)
ret=max(ret,ans-e[edge[i].from][edge[i].to]+g[edge[i].from][edge[i].to]);
printf("%.2f\n",ret*m);
}
return 0;
}