ACM Contest and Blackout (最小和次小生成树)
In order to prepare the “The First National ACM School Contest” (in 20??) the major of the city decided to provide all the schools with a reliable source of power. (The major is really afraid of blackoutsJ). So, in order to do that, power station “Future” and one school (doesn’t matter which one) must be connected; in addition, some schools must be connected as well.
You may assume that a school has a reliable source of power if it’s connected directly to “Future”, or to any other school that has a reliable source of power. You are given the cost of connection between some schools. The major has decided to pick out two the cheapest connection plans – the cost of the
connection is equal to the sum of the connections between the schools. Your task is to help the major— find the cost of the two cheapest connection plans.
Input
The Input starts with the number of test cases, T (1 < T < 15) on a line. Then T test cases follow. The first line of every test case contains two numbers, which are separated by a space, N (3 < N < 100) the number of schools in the city, and M the number of possible connections among them. Next M lines contain three numbers Ai, Bi, Ci, where Ci is the cost of the connection (1 < Ci < 300) between schools Ai and Bi . The schools are numbered with integers in the range 1 to N.
Output
For every test case print only one line of output. This line should contain two numbers separated by a single space – the cost of two the cheapest connection plans. Let S1 be the cheapest cost and S2 the next cheapest cost. It’s important, that S1 = S2 if and only if there are two cheapest plans, otherwise S1 < S2. You can assume that it is always possible to find the costs S1 and S2.
Sample Input
2
5 8
1 3 75
3 4 51
2 4 19
3 2 95
2 5 42
5 4 31
1 2 9
3 5 66
9 14
1 2 4
1 8 8
2 8 11
3 2 8
8 9 7
8 7 1
7 9 6
9 3 2
3 4 7
3 6 4
7 6 2
4 6 14
4 5 9
5 6 10
Sample Output
110 121
37 37
题意: 求最小生成树和次小生成树,最小直接套模板即可,说一下如何求次小生成树,次小生成树与最小生成树其实就是相差一条边,就是去掉最小生成树中的某一边,再加一条没用过的边,至于去哪一条边,就得遍历一遍,比较得结果了
AC代码:
#include<stdio.h>
#include<iostream>
#include<string.h>
#include<algorithm>
using namespace std;
int f[11000],n,book[11000];
char c,d;
struct pp
{
int a,b,c;
} p[11000];
bool cmp(pp xx,pp yy)
{
return xx.c<yy.c;
}
void init()
{
int i;
for(i=1; i<=n; i++)
f[i]=i;
}
int find(int x)
{
if(f[x]==x)
return x;
else
return f[x]=find(f[x]);
}
void merge(int x,int y)
{
int xx,yy;
xx=find(x);
yy=find(y);
if(xx!=yy)
f[yy]=xx;
}
int main()
{
int m,t,i,j,k;
scanf("%d",&t);
while(t--)
{
memset(book,0,sizeof(book));
scanf("%d%d",&n,&m);
init();
for(i=0; i<m; i++)
scanf("%d%d%d",&p[i].a,&p[i].b,&p[i].c);
sort(p,p+m,cmp);
int ans=0,sum=0;
for(i=0; i<m; i++)
{
if(find(p[i].a)==find(p[i].b))
continue;
merge(p[i].a,p[i].b);
book[i]=1;//标记最小生成树用过那条边
ans++;
sum+=p[i].c;
if(ans==n-1)
break;
}
printf("%d ",sum);
int minn=0x3f3f3f;
for(i=0; i<m; i++)//求次小生成树
{
if(book[i])//如果边被用过
{
ans=0;
sum=0;
init();//一定要初始化
for(j=0; j<m; j++)
{
if(i==j)//跳过这条边
continue;
if(find(p[j].a)==find(p[j].b))
continue;
merge(p[j].a,p[j].b);
ans++;
sum+=p[j].c;
if(ans==n-1)
{
if(sum<minn)//遍历比较找到次小
minn=sum;
break;
}
}
}
}
printf("%d\n",minn);
}
return 0;
}