ural 1416 Confidential 次小生成树
/*
题目:
很裸的次小生成树题,要求先给出最小生成树的值,若有不连通的输出-1,
接着需要输出次小生成树的值
分析:
可以选择prim或kruskal算法做,我的做法是用prim做的,具体看代码注释
*/
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
#define X 503
#define INF 10000000
int path[X][X],map[X][X],dis[X],pre[X],n,m;
bool use[X],visit[X][X];
int prim()
{
memset(pre,0,sizeof(pre)); //前趋顶点
memset(visit,false,sizeof(visit)); //标记该边是否在最小生成树中
memset(use,false,sizeof(use)); //标记该边是否已经在最小生成树中
memset(path,0,sizeof(path)); //标记该两顶点之间的最大长度的边
for(int i=1;i<=n;i++)
dis[i] = INF;
dis[1] = 0;
int k,MIN,ans = 0;
for(int i=0;i<n;i++)
{
MIN = INF;
for(int j=1;j<=n;j++)
if(!use[j]&&dis[j]<MIN)
MIN = dis[k=j];
if(MIN==INF) //若当前就没有连通路的话,直接退出
return INF;
int p = pre[k];
visit[p][k] = visit[k][p] = true;//表示该边在生成树中
path[p][k] = MIN; //表示最小生成生成树中的边的长度
for(int j=1;j<=n;j++)
if(use[j]) //更新所有已在最小生成树中的点到k的距离path[j][k]
path[j][k] = path[j][p]>path[p][k]?path[j][p]:path[p][k];
ans += MIN;
use[k] = true;
for(int j=1;j<=n;j++)
if(!use[j]&&dis[j]>map[k][j])
dis[j] = map[k][j],pre[j] = k;//如果k能把dis[j]更新,表示k是j的pre
}
return ans;
}
int main()
{
freopen("sum.in","r",stdin);
freopen("sum.out","w",stdout);
int x,y,z;
while(cin>>n>>m)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
map[i][j] = INF;
while(m--)
{
scanf("%d%d%d",&x,&y,&z);
map[x][y] = map[y][x] = z;
}
int ans = prim(); //求出一棵最小生成树
if(ans==INF)
{
cout<<"Cost: "<<-1<<endl;
cout<<"Cost: "<<-1<<endl;
}
else
{
cout<<"Cost: "<<ans<<endl;
int ans2 = INF;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(!visit[i][j]&&map[i][j]<INF)
{//枚举边,若不在最小生成树中时,且该边是连通的,用它替换最小生成树中的一条边
int temp = ans+map[i][j]-path[i][j];
if(temp<ans2)
ans2 = temp;
}
if(ans2==INF)
cout<<"Cost: "<<-1<<endl;
else
cout<<"Cost: "<<ans2<<endl;
}
}
return 0;
}