nyoj118修路方案(次小生成树)

http://acm.nyist.net/JudgeOnline/problem.php?pid=11

次小生成树:生成树权值第二小的生成树,当存在一条边跟最小生成树上的边相等时,次小生成树跟最小生成树相等。

题目解析:先用prim算法生成次小生成树,并且保存生成树上每个节点的前一个节点,并且保存生成树上用过的边,然后枚举没有用过的边,就会形成一个环,然后判断环上除新加入的边外的边有没有与加入的新边相等的,如果有相等的,就说明存在次小生成树。

代码如下:


#include<cstdio>
002. #include<cstring>
003. #include<algorithm>
004. using namespace std;
005. const int INF=0xffffff;
006. int map[505][505];
007. int pre[505];
008. int f[505][505];
009. int flag[505];
010. int dis[505];
011. int m,n;
012.  
013.  
014. void prim()
015. {
016. memset(flag,0,sizeof(flag));
017. int pos=1;
018. dis[1]=0;
019. flag[1]=1;
020. for(int i=1;i<=n;i++)
021. pre[i]=1;
022. for(int i=2;i<=n;i++)
023. dis[i]=map[pos][i];
024. for(int j=1;j<n;j++)
025. {
026. int Min=999999999;
027. for(int i=1;i<=n;i++)
028. {
029. if(!flag[i]&&dis[i]<Min)
030. {
031. Min=dis[i];
032. pos=i;
033. }
034. }
035. int q=pre[pos];
036. flag[pos]=1;
037. f[q][pos]=f[pos][q]=0;
038. for(int i=1;i<=n;i++)
039. {
040. if(!flag[i]&&map[pos][i]<dis[i])
041. {
042. dis[i]=map[pos][i];
043. pre[i]=pos;
044. }
045. }
046. }
047.  
048. }
049. int cmst()
050. {
051. for(int i=1;i<=n;i++)            //枚举在最小生成树上的每一个点
052. {
053. for(int j=1;j<=n;j++)
054. {
055. if(f[i][j])             //此边没有用过
056. {
057. int t=map[i][j];
058. int v=i,v1=v;
059. int u=j;
060. int ff=0;
061. while(1)
062. {
063. if(map[v1][pre[v1]]==t)
064. {
065. ff=1;
066. break;
067. }
068. if(v1==u)
069. break;
070. if(v1==pre[v1])
071. {
072. ff=0;
073. break;
074. }
075. v1=pre[v1];
076. }
077. while(!ff)
078. {
079. if(map[u][pre[u]]==t)
080. {
081. ff=1;
082. break;
083. }
084. if(v==u)
085. break;
086. if(u==pre[u])
087. {
088. ff=0;
089. break;
090. }
091. u=pre[u];
092. }
093. if(ff) return 1;
094. }
095. }
096. }
097. return 0;
098. }
099. int main()
100. {
101. int icase;
102. scanf("%d",&icase);
103. while(icase--)
104. {
105.  
106. int a,b,c;
107. scanf("%d%d",&n,&m);
108. memset(map,2,sizeof(map));
109. memset(f,0,sizeof(f));
110. for(int i=1;i<=m;i++)
111. {
112. scanf("%d%d%d",&a,&b,&c);
113. f[a][b]=f[b][a]=1;
114. map[a][b]=map[b][a]=c;
115. }
116. prim();
117. if(cmst())
118. printf("Yes\n");
119. else
120. printf("No\n");
121. }
122. return 0;
123. }


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值