题意:
给你N个点,M条边,其中有重边,A,B,C表示A到B的价格为C,连接所有的点,求出最小的价格,如果无法连接所有的点的话就输出No way。如果没有次小生成树的话就输出No second way。如果有的话就输出次小生成树的值。
题解:
次小生成树,做完这道题之后我发现我以前做的都是没有重边的次小生成树,所以一开始我就用prim做这道题,发现难的要死,后来才知道次小生成树的题如果有重边是不能删除的,要保留下来,所以这道题用Kruskal比较好。通过这道题也让我知道了我以前的Kruskal的次小生成树的模板不太行,要重新回去弄一下。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
const int MAXN=205;
struct node
{
int u,v,w;
bool del,used;
}map[MAXN];
int fa[105];
int n,m,cnt;
bool flag;
bool cmp(node c,node d)
{
return c.w<d.w;
}
void init()
{
for(int i=1;i<=n;i++)
fa[i]=i;
}
int find(int p)
{
return p==fa[p]? p:find(fa[p]);
}
int Kruskal()
{
int sum=0,num=0;
init();
for(int i=0;i<m;i++)
{
if(map[i].del)
continue;
int P=find(map[i].u);
int Q=find(map[i].v);
if(P!=Q)
{
sum+=map[i].w;
fa[P]=Q;
if(!flag) map[i].used=true;
num++;
}
if(num>=n-1)
break;
}
if(num>=n-1)
return sum;
else
return INF;
}
int main()
{
int t,k=1;
scanf("%d",&t);
while(t--)
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
scanf("%d%d%d",&map[i].u,&map[i].v,&map[i].w);
map[i].del=map[i].used=false;
}
sort(map,map+m,cmp);
flag=false;
int mst=Kruskal();
// printf("%d\n",mst);
flag=true;
int minn=INF;
for(int i=0;i<m;i++)
{
if(map[i].used)
{
map[i].del=true;//标记要删除的原最小生成树的边。
minn=min(minn,Kruskal());
map[i].del=false;
}
}
printf("Case #%d : ",k++);
if(mst==INF)
printf("No way\n");
else if(minn==INF)
printf("No second way\n");
else
printf("%d\n",minn);
}
}