思路:
- 最小生成树的唯一性,做法有两种。
- 多次 Kruskal。第一次 Kruskal 将最小生成树用到的所有边高亮并记录 ans,然后逐一删去某条边再 Kruaskal,若某次结果与 ans相同,则可证明树 not unique。注意可能删去某条边后原图不连通,要加入判断,否则会 WA。优化:因为边数是固定的,所以仅将权值重复且用到的边高亮即可,如果边权唯一则不需删除之(只需要多加一个 same[])。
- 次小生成树
代码:
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 110;
int N,M;
int ans;
int par[maxn];
bool book[maxn * maxn / 2];
struct EDGE{
int l,r,w;
friend bool operator < (EDGE a , EDGE b)
{
return a.w < b.w;
}
}edge[maxn * maxn / 2];
void ADDEDGE(int i,int l,int r,int w){
edge[i].l = l;
edge[i].r = r;
edge[i].w = w;
return ;
}
void INIT(){
memset(book , 0 , sizeof(book));
return ;
}
int FIND(int i){
return par[i] == -1 ? i : par[i] = FIND(par[i]);
}
void UNION(int l,int r){
int parl = FIND(l);
int parr = FIND(r);
par[parr] = parl;
return ;
}
int KRUSKAL(int jump){
memset(par , -1 , sizeof(par));
int tp = 0;
for(int i=0;i<M;i++){
if(i == jump)
continue;
int l = edge[i].l;
int r = edge[i].r;
int parl = FIND(l);
int parr = FIND(r);
if(parl != parr){
UNION(l,r);
tp += edge[i].w;
if(jump == -1)
book[i] = true;
}
}
for(int i=1;i<N;i++){
if(FIND(i) != FIND(i+1))
{
tp = -1;
break;
}
}
return tp;
}
int main(){
int T;cin>>T;
while(T--){
INIT();
cin>>N>>M;
for(int i=0;i<M;i++){
int l,r,w;
cin>>l>>r>>w;
ADDEDGE(i,l,r,w);
}
sort(edge , edge+M);
ans = KRUSKAL(-1);
for(int i=0;i<M;i++){
if(book[i]){
int tp;
tp = KRUSKAL(i);
if(tp == ans){
ans = -1;
break;
}
}
}
if(ans == -1)
cout<<"Not Unique!"<<endl;
else
cout<<ans<<endl;
}
return 0;
}
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 110;
int N,M;
int ans;
int par[maxn];
bool book[maxn * maxn / 2];
bool same[maxn * maxn / 2];
struct EDGE{
int l,r,w;
friend bool operator < (EDGE a , EDGE b)
{
return a.w < b.w;
}
}edge[maxn * maxn / 2];
void ADDEDGE(int i,int l,int r,int w){
edge[i].l = l;
edge[i].r = r;
edge[i].w = w;
return ;
}
void INIT(){
memset(book , 0 , sizeof(book));
memset(same , 0 , sizeof(same));
return ;
}
int FIND(int i){
return par[i] == -1 ? i : par[i] = FIND(par[i]);
}
void UNION(int l,int r){
int parl = FIND(l);
int parr = FIND(r);
par[parr] = parl;
return ;
}
int KRUSKAL(int jump){
memset(par , -1 , sizeof(par));
int tp = 0;
for(int i=0;i<M;i++){
if(i == jump)
continue;
int l = edge[i].l;
int r = edge[i].r;
int parl = FIND(l);
int parr = FIND(r);
if(parl != parr){
UNION(l,r);
tp += edge[i].w;
if(jump == -1)
book[i] = true;
}
}
for(int i=1;i<N;i++){
if(FIND(i) != FIND(i+1))
{
tp = -1;
break;
}
}
return tp;
}
int main(){
int T;cin>>T;
while(T--){
INIT();
cin>>N>>M;
for(int i=0;i<M;i++){
int l,r,w;
cin>>l>>r>>w;
ADDEDGE(i,l,r,w);
}
sort(edge , edge+M);
for(int i=1;i<M;i++)
if(edge[i-1].w == edge[i].w)
same[i-1] = same[i] = true;
ans = KRUSKAL(-1);
for(int i=0;i<M;i++){
if(book[i] && same[i]){
int tp;
tp = KRUSKAL(i);
if(tp == ans){
ans = -1;
break;
}
}
}
if(ans == -1)
cout<<"Not Unique!"<<endl;
else
cout<<ans<<endl;
}
return 0;
}