您的位置:首页 > 其它

NYOJ 118 Prim求次小生成树

2016-07-20 12:11 183 查看
传送门

思路:

这里用Maxlen记录在最小生成树里的点两点之间存在的最大的权值边,

然后枚举每条没有加入的边,如果有很这两点之间在最小生成树里的最大边相等的,就说明有次小生成树。

#include <iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
const int MAX=505;
int T,m,n;//m点的数量,n边的数量
int mp[MAX][MAX],Maxlen[MAX][MAX],dis[MAX];
int pre[MAX];//生成树里每个点的父节点
bool vis[MAX];
void init(){
for(int i=1;i<=m;i++)
for(int j=1;j<=m;j++)
mp[i][j]=(i==j?0:INF);
}
int Prim(){
int mi,minI,pr;
memset(vis,0,sizeof(vis));
for(int i=1;i<=m;i++){dis[i]=mp[1][i];pre[i]=1;}
vis[1]=1;
int sum=0;
for(int i=1;i<m;i++){
mi=INF;
for(int j=1;j<=m;j++){
if(!vis[j]&&dis[j]<mi){
minI=j;
mi=dis[j];
}
}
if(mi==INF)return -1;
pr=pre[minI];
Maxlen[pr][minI]=Maxlen[minI][pr]=mi;
for(int j=1;j<=m;j++){
if(vis[j])Maxlen[minI][j]=Maxlen[j][minI]=max(mi,Maxlen[pr][j]);
}
vis[minI]=1;
sum+=mi;
for(int j=1;j<=m;j++){
if(!vis[j]&&dis[j]>mp[minI][j]){
dis[j]=mp[minI][j];
pre[j]=minI;
}
}
}
return sum;
}
bool secondMST(){
for(int i=1;i<=m;i++){
for(int j=1;j<=m;j++){
if(pre[i]==j||pre[j]==i||i==j)continue;
if(mp[i][j]==Maxlen[i][j])return 1;
}
}
return 0;
}
int main()
{
int a,b,l;
scanf("%d",&T);
while(T--){
scanf("%d%d",&m,&n);
init();
while(n--){
scanf("%d%d%d",&a,&b,&l);
if(mp[a][b])mp[a][b]=mp[b][a]=min(mp[a][b],l);
else mp[a][b]=mp[b][a]=l;
}
Prim();
/*for(int i=1;i<=m;i++){
for(int j=1;j<=m;j++){
cout<<i<<" "<<j<<" "<<Maxlen[i][j]<<endl;
}
}*/
if(secondMST())printf("Yes\n");
else printf("No\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: