题意:求一幅无向图的最小生成树与最小生成树,不存在输出-1
分析:Kruskal求最小生成树,标记用过的边。求次小生成树时,依次枚举用过的边,将其去除后再求最小生成树,得出所有情况下的最小的生成树就是次小的生成树。可以证明:最小生成树与次小生成树之间仅有一条边不同。
样例:
input | output |
---|---|
4 6 1 2 2 2 3 2 3 4 2 4 1 2 1 3 1 2 4 1 | Cost: 4 Cost: 4 |
3 2 1 2 2 2 3 2 | Cost: 4 Cost: -1 |
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int MAXN = 505;
const int MAXM = 0x7fffffff;
int n,m;
int use_num ;
int wei;
struct Edge
{
int u,v,w;
bool operator <(const Edge& ee)
{
return w<ee.w;
}
}e[MAXN*MAXN];
int used[MAXN],pre[MAXN];
int finds(int x)
{
if(pre[x]==-1)
return x;
return pre[x]=finds(pre[x]);
}
int Kruskal()
{
//int flag = 0;.
int fx,fy;
use_num = 0;
wei = 0;
fill_n(pre,n+1,-1);
for(int i = 0;i<m;i++)
{
fx=finds(e[i].u);fy=finds(e[i].v);
if(fx!=fy)
{
pre[fx]=fy;
used[use_num++] = i;
wei+=e[i].w;
if(use_num == n-1)
return wei;
}
}
// printf("m= %d use")
return -1;
}
int sec_kruskal()
{
int flag =0;
int fx,fy,count_num;
int num = MAXM;
int sum;
for(int i=0;i<use_num;i++)
{
fill_n(pre,n+1,-1);
count_num = 0;sum=0;flag=0;
for(int j=0;j<m;j++)
{
if(j==used[i])
continue;
fx=finds(e[j].u);fy=finds(e[j].v);
if(fx!=fy)
{
pre[fx]=fy;
count_num++;
sum+=e[j].w;
if(count_num == n-1)
{
flag = 1;
break;
}
}
}
if(flag&&sum<num)
{
num=sum;
}
}
if(num==MAXM)
return -1;
else
return num;
}
int main()
{
//int n,m;
int u,v,w;
int fmin,smin;
while(scanf("%d %d",&n,&m)!=EOF)
{
for(int i=0;i<m;i++)
{
scanf("%d %d %d",&u,&v,&w);
e[i] = (Edge){u,v,w};
}
sort(e,e+m);
fmin = Kruskal();
smin = sec_kruskal();
printf("Cost: %d\n",fmin);
printf("Cost: %d\n",smin);
}
}