题意:给你一个n个点m条边的无向图,问你该图的最小生成树是否唯一?如果唯一输出,树的权值,否则输出'Not Unique!'.
思路:
本题求该无向图的次小生成树的权值是否等于最小生成树的权值,一个图的次小生成树的权值<=最小生成树的权值,至少有一条边与最小生成树不同,所以可以枚举最小生成树上的边,删除之后用剩下的边重新求最小生成树,求出新生成的最小生成树中权值最小就是为次小生成树的权值
题目
Trick:删除一条边之后原图可能不连通,返回-1,注意考虑清楚
#include <cstdio>
#include <queue>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <vector>
#include <map>
#include <string>
#include <set>
#include <ctime>
#include <cmath>
#include <cctype>
using namespace std;
#define maxn 110
const int maxm = 100*100+10;
#define LL long long
int cas=1,T;
struct Edge
{
int u,v,dist;
int id; //边的编号
Edge(){}
Edge(int u,int v,int dist,int id):u(u),v(v),dist(dist),id(id){}
bool operator < (const Edge&rhs)const
{
return dist < rhs.dist;
}
};
int n,m;
Edge edges[maxm];
int pre[maxn];
vector <int> E; //保存最小生成树的边的编号
int Find(int x)
{
return pre[x]==-1?x:pre[x]=Find(pre[x]);
}
void init()
{
m=0;
memset(pre,-1,sizeof(pre));
}
void AddEdge(int u,int v,int dist,int id)
{
edges[m++]=Edge(u,v,dist,id);
}
int Kruskal(int ID)
{
memset(pre,-1,sizeof(pre));
E.clear();
int sum = 0;
int cnt = 0;
sort(edges,edges+m);
for (int i = 0;i<m;i++)
{
if (edges[i].id == ID)
continue;
int u = edges[i].u;
int v = edges[i].v;
if (Find(u)!=Find(v))
{
E.push_back(edges[i].id);
pre[Find(u)]=Find(v);
sum+=edges[i].dist;
if (++cnt >=n-1)
break;
}
}
if (cnt < n-1)
return -1;
return sum;
}
int main()
{
//freopen("in","r",stdin);
scanf("%d",&T);
while (T--)
{
int mm;
scanf("%d%d",&n,&mm);
init();
for (int i = 0;i<mm;i++)
{
int u,v,d;
scanf("%d%d%d",&u,&v,&d);
AddEdge(u,v,d,i);
}
int ans1 = Kruskal(-1);
int ans2 = 1<<20;
vector <int>EE(E);
for (int i = 0;i<EE.size();i++)
{
int temp = Kruskal(EE[i]);
if (temp == -1)
continue;
ans2 = min(ans2,temp);
if (ans2 == ans1)
break;
}
if (ans1 == ans2)
puts("Not Unique!");
else
printf("%d\n",ans1);
}
//printf("time=%.3lf",(double)clock()/CLOCKS_PER_SEC);
return 0;
}
题目