题目链接
题目大意:给定无向图,判断最小生成树是否唯一。
思路:求非严格的最小生成树,如果代价等于最小生成树,说明最小生成树不唯一,反之唯一。
非严格次小生成树求法:在求出最小生成树的基础上,枚举每一条没有加进MST里的边<i,j>,把他加进去得到一个环,再删去这个环原先的最长的边(即:MST中i到j路径上的最长边,通过树形dp 维护maxedge[i][j],记录mst中i j路径上最大边权值),替换之后得到的所有权值和中 最小的就是次小生成树了。
(但是这样得到的是非严格的次小生成树,因为这个环原先的最长的边有可能和加进去的边权值相等,
最终得到的次小生成树的代价可能等于MST,即:非严格的次小生成树。
严格次小生成树还需要维护mst中i j路径上次大边权值,替换的时候如果<i,j>路径上最大边权值和<i,j>边权相等,就删去次大值。
这题求非严格的次小生成树就好了。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<stdlib.h>
#include<string.h>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<math.h>
#include<set>
using namespace std;
const int maxn = 2e2+7;
const int INF = 1e9+7;
//求次小生成树
//在求出最小生成树的基础上,枚举每一条没有加进MST里的边,加进去得到带环的树,
//把得到的环里的最长的边删去,就得到一个生成树的权值了,枚举的最小结果就是次小生成树的代价
struct node
{
int d;
int v;
friend bool operator < (const node &a,const node &b)
{
return a.d > b.d;
}
}h,t;
priority_queue<node> q;
int n,m;
int g[maxn][maxn];
int dist[maxn];
bool vis[maxn];
int pre[maxn];//最小生成树中该顶点的父节点
bool used[maxn][maxn];//i->j这条边有没有用过
int maxedge[maxn][maxn];//i j路径上的最大边 利用树上dp更新
//转移方程 maxedge[i][j]=max(maxedge[i][fa[j]],dist[j])
void init()
{
fill(g[0],g[0]+maxn*maxn,INF);
memset(vis,0,sizeof(vis));
while(q.size()) q.pop();
fill(dist,dist+maxn,INF);
memset(pre,0,sizeof(pre));
memset(maxedge,0,sizeof(maxedge));
memset(used,0,sizeof(used));
}
int prim()
{
int ans=0;
dist[1]=0;
t.d=0,t.v=1;
q.push(t);
while(q.size())
{
h=q.top(),q.pop();
if(vis[h.v]) continue;
vis[h.v]=1;//入树
ans+=h.d;
used[h.v][pre[h.v]]=used[pre[h.v]][h.v]=1;//边入树
for(int i=1;i<=n;i++)
{
if(vis[i])//i已经在mst里面
{
//更新h.v与i的路径上最大边
maxedge[h.v][i]=maxedge[i][h.v]=max(maxedge[i][pre[h.v]],h.d);
}
if(!vis[i] && dist[i] > g[h.v][i])
{
dist[i] = g[h.v][i];
pre[i]=h.v;
t.d=dist[i],t.v=i;
q.push(t);
}
}
}
return ans;
}
void solve()
{
int mst=prim();
int sec_mst=INF;
for(int i=1;i<=n;i++)
{
for(int j=1+i;j<=n;j++)
{
if(g[i][j]==INF || used[i][j]) continue;//必须是mst中没有的边
sec_mst=min(sec_mst,mst-maxedge[i][j]+g[i][j]);
}
}
if(mst == sec_mst) printf("Not Unique!\n");
else printf("%d\n",mst);
}
int main()
{
int T;
cin>>T;
for(int tt=1;tt<=T;tt++)
{
init();
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
int v,u,w;
scanf("%d %d %d",&v,&u,&w);
g[u][v]=g[v][u]=min(g[u][v],w);
}
solve();
}
return 0;
}