ACM Contest and Blackout
题意:
——求最小生成树和次最小生成树,一定存在。
t组样例
n,m分别代表n个城镇,m条双向边
下面m行边的信息。
解题思路:
并查集版: 最小生成树和次最小生成树模板
——如何求:次最小生成树
- 求出最小生成树,标记用了哪些边,
- 被标记的n-1条边每次只有一个不用,再求最小生成树,
- 会得到(n-1)个最小生成树的值,最小的一定是次最小生成树的值。
——为什么。
- 第一次求最小生成树,被标记的边一定都是最优的,
- 如果有一条边不用,再求最小生成树,得到的一定是次最小生成树
- 但去掉哪条边合适呢,不清楚,需要模拟出所有情况,找最小。
代码:Krusk
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=110;
int f[N],book[N*N/2];
int n,m;
struct Node{
int u,v,w;
}q[N*N/2];
bool cmp(Node a,Node b)
{
return a.w<b.w;
}
void init()
{
for(int i=1;i<=n;i++)
f[i]=i;
}
int find(int x)
{
if(x!=f[x])
f[x]=find(f[x]);
return f[x];
}
int Merge(int u,int v)
{
int tu=find(u);
int tv=find(v);
if(tu!=tv)
{
f[tv]=tu;
return 1;
}
return 0;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
scanf("%d %d %d",&q[i].u,&q[i].v,&q[i].w);
sort(q+1,q+1+m,cmp);
init();
memset(book,0,sizeof(book));
int cnt1=0,sum=0;
for(int i=1;i<=m;i++)
{
if(Merge(q[i].u,q[i].v)==1)
{
book[i]=1;
sum+=q[i].w;
cnt1++;
if(cnt1==n-1)
break;
}
}
int mind=sum;
int Cmind=INF;
for(int i=1;i<=m;i++)
{
if(book[i]==1)
{
init();
sum=0;cnt1=0;
for(int j=1;j<=m;j++)
{
if(i==j) continue;
if(Merge(q[j].u,q[j].v)==1)
{
sum+=q[j].w;
cnt1++;
if(cnt1==n-1)
{
Cmind=min(Cmind,sum);
break;
}
}
}
}
}
printf("%d %d\n",mind,Cmind);
}
return 0;
}