[bzoj4986]MiniumCut

来源:互联网 发布:java api全部包类 编辑:程序博客网 时间:2024/06/14 19:24

题目大意

一副无向图,给定任意两点间最小割,请构造出这样的图,或判断无解。

构造

显然构造出最小割树即可。
容易发现最小割树一定是一颗最大生成树。
不同的最大生成树之间任意两点间最小割不变。
因此做一颗最大生成树,看它是否满足条件即可。

#include<cstdio> #include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)using namespace std;const int maxn=100+10,inf=1000000000;struct dong{    int x,y,z;    friend bool operator <(dong a,dong b){        return a.z>b.z;    }} edge[maxn*maxn];int dis[maxn][maxn],fa[maxn],data[maxn],zz[maxn],rk[maxn],ans[maxn][3];bool bz[maxn];int i,j,k,l,t,n,m,tot,top;bool czy;int getfa(int x){    return fa[x]?getfa(fa[x]):x;}void merge(int x,int y,int z){    top++;    ans[top][0]=x;ans[top][1]=y;ans[top][2]=z;    x=getfa(x);y=getfa(y);    if (rk[x]<rk[y]) swap(x,y);    fa[y]=x;    data[y]=z;    if (rk[x]==rk[y]) rk[x]++;}int ask(int x,int y){    int t=inf;    int j=x;    while (j){        bz[j]=1;        zz[j]=t;        t=min(t,data[j]);        j=fa[j];    }    t=inf;    j=y;    while (j){        if (bz[j]) break;        t=min(t,data[j]);        j=fa[j];    }    t=min(t,zz[j]);    j=x;    while (j){        bz[j]=0;        j=fa[j];    }    return t;}int main(){    freopen("cut.in","r",stdin);freopen("cut.out","w",stdout);    scanf("%d",&n);    fo(i,1,n)        fo(j,1,n){            scanf("%d",&dis[i][j]);            if (i!=j){                tot++;                edge[tot].x=i;                edge[tot].y=j;                edge[tot].z=dis[i][j];            }        }    sort(edge+1,edge+tot+1);    fo(i,1,tot){        j=edge[i].x;k=edge[i].y;l=edge[i].z;        if (getfa(j)!=getfa(k)) merge(j,k,l);    }    czy=1;    fo(i,1,n-1){        fo(j,i+1,n)            if (ask(i,j)!=dis[i][j]){                czy=0;                break;            }        if (!czy) break;    }    if (!czy) printf("-1\n");    else{        printf("%d\n",n-1);        fo(i,1,n-1) printf("%d %d %d\n",ans[i][0],ans[i][1],ans[i][2]);    }}
原创粉丝点击