POJ1679 The Unique MST - 非严格次小生成树

题目大意:给定一个无向连通图,回答它的最小生成树是否是唯一的。

思路:先求出这个图的最小生成树,然后枚举每条不在最小生成树上的边(u,v)。由于这条边(u,v)与最小生成树上连接u和v两点的链构成了一个环,因此可以通过倍增LCA找到链上最小的边,在答案中删除之并加上枚举的边(u,v),判断与之前最小生成树是否相等即可。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100+100,M=10000+100;
int n,m;
struct node{
    int to,nxt,w;
}e[M];
int head[N],tot;
void add(int u,int v,int w) {
    e[++tot]=(node){v,head[u],w};
    head[u]=tot;
}
int fa[N];
int find(int u) {
    return fa[u]==u?u:fa[u]=find(fa[u]);
}
struct ed {
    int u,v,w;
}E[M];
bool cmp(ed a,ed b) {
    return a.w<b.w;
}
int mst;
bool yes[M];
void kruskal() {
    int cnt=0;
    mst=0;
    sort(E+1,E+m+1,cmp);
    for(int i=1;i<=n;i++) fa[i]=i;
    for(int i=1;i<=m;i++) {
        int u=E[i].u,v=E[i].v,w=E[i].w;
        int f1=find(u),f2=find(v);
        if(f1!=f2) {
            mst+=w;
            yes[i]=true;
            if(rand()%2) fa[f1]=f2;
            else fa[f2]=f1;
            cnt++;
            if(cnt==n-1) return ;
        }
    }
}
int dep[N],dad[N],f[N][25][3];
void dfs(int u) {
    for(int i=head[u];i;i=e[i].nxt) {
        int v=e[i].to;
        if(!dep[v]) {
            dep[v]=dep[u]+1;
            f[v][0][0]=u;
            f[v][0][1]=e[i].w;
            dad[v]=u;
            dfs(v);    
        }
        
    }
}
void pre() {
    for(int i=1;i<=20;i++) {
        for(int j=1;j<=n;j++) {
            f[j][i][0]=f[f[j][i-1][0]][i-1][0];
            f[j][i][1]=max(f[j][i-1][1],f[f[j][i-1][0]][i-1][1]);
        }
    }
}
int query(int u,int v) {
    int ans=-(1<<30);
    if(dep[u]<dep[v]) swap(u,v);
    for(int i=20;i;i--) {
        if(dep[f[u][i][0]]>=dep[v]) {
            ans=max(ans,f[u][i][1]);
            u=f[u][i][0];
        }
    }
    if(u==v) return ans;
    for(int i=20;i;i--) {
        if(f[u][i][0]!=f[v][i][0]) {
            ans=max(ans,max(f[u][i][1],f[v][i][1]));
            u=f[u][i][0];
            v=f[v][i][0];
        }
    }
    ans=max(ans,max(f[u][0][1],f[v][0][1]));
    return ans;
}
void solve() {
    int ans=(1<<30);
    for(int i=1;i<=n;i++) {
        if(!dep[i]) {
            dad[i]=i;
            dep[i]=1;
            dfs(i);
        }
    }
    pre();
    for(int i=1;i<=m;i++) {
        int u=E[i].u,v=E[i].v,w=E[i].w;
        if(!yes[i]) ans=min(ans,mst-query(u,v)+w);
    }
    if(ans==mst) printf("Not Unique!\n");
    else printf("%d\n",mst);
}
int main() {
    int t;
    scanf("%d",&t);
    while(t--) {
        tot=0;
        memset(e,0,sizeof(e));
        memset(head,0,sizeof(head));
        memset(yes,0,sizeof(yes));
        memset(dep,0,sizeof(dep));
        memset(f,0,sizeof(f));
        memset(E,0,sizeof(E));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=m;i++) {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            E[i]=(ed){u,v,w};
            add(u,v,w);
        }
        kruskal();
        solve();
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Loi-Brilliant/p/9147223.html