题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1416
题意:求最小生成树和次小生成树,没有输出-1
题解:次小生成树的其中一种求法是标记每一个点互相连接的最大边,标记最小生成树都用了那些边,然后遍历那些没用到的边,多链接一条边后去掉其中最大的一条边,找其中的最小值。
AC代码:
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
#define _for(i,a,b) for(int i=a;i<=b;i++)
const int inf = 0x3f3f3f;
const int maxn = 505;
int n,m,a[maxn][maxn],dist[maxn],used[maxn][maxn],vis[maxn],maxmap[maxn][maxn],pre[maxn];
int prime()
{
int ans = 0;
_for(i,1,n)
{
vis[i]=0;
dist[i]=a[1][i];
pre[i]=1;
}
vis[1]=1;
pre[1]=0;
_for(i,2,n)
{
int v=0;
int u = inf;
_for(j,1,n)
{
if(vis[j]==0&&u>dist[j])
{
u=dist[j];
v = j;
}
}
if(u==inf)return inf;
vis[v]=1;
ans+=u;
used[v][pre[v]]=used[pre[v]][v]=1;
_for(j,1,n)
{
if(vis[j])
{
if(j!=v)maxmap[j][v]=maxmap[v][j]=max(maxmap[j][pre[v]],dist[v]);
}
else
{
if(dist[j]>a[v][j])
{
dist[j]=a[v][j];
pre[j]=v;
}
}
}
}
return ans;
}
int main(int argc, char const *argv[])
{
//freopen("in.txt","r",stdin);
//freopen("out.txt","w",stdout);
cin>>n>>m;
_for(i,1,n)
{
_for(j,1,n)
{
if(i!=j)a[i][j]=inf;
else a[i][j]=0;
}
}
_for(i,1,m)
{
int x,y,z;
cin>>x>>y>>z;
a[x][y]=a[y][x]=min(a[x][y],z);
}
int now = prime();
int ans = inf;
_for(i,1,n)
{
_for(j,i+1,n)
{
if(!used[i][j]&&a[i][j]!=inf)
{
ans = min(ans,now+a[i][j]-maxmap[i][j]);
}
}
}
if(now==inf)cout<<"Cost: "<<"-1"<<endl;
else cout<<"Cost: "<<now<<endl;
if(ans==inf) cout<<"Cost: "<<"-1"<<endl;
else cout<<"Cost: "<<ans<<endl;
return 0;
}