BZOJ 2768チャンピオン調査(最小割)

2494 ワード

タイトルリンク:http://61.187.179.132/JudgeOnline/problem.php?id=2768
題意:無方向図を与え、各点に0または1の値がある.各ポイントの値0または1を再設定します.再設定後の点と元の点がx個ある点の値が異なるとする.再設定後、uとvの値が異なるようにy辺(u,v)があります.x+yを最小化します.
考え方:初期値が1の場合、原点はその辺に接続されます.そうでなければ、そのポイントはエッジに接続されます.エッジ(u,v)について、uとvの値が異なると、エッジが接続されます.最小割を求める.左側が切り取られると、それを0に変更することを示す.右側が切られると、それを1に変更することを示します.中間が切られると両側の衝突を表す.
 
struct node

{

    int v,cap,next;

};









node edges[N];

int head[N],e;









void add(int u,int v,int cap)

{

    edges[e].v=v;

    edges[e].cap=cap;

    edges[e].next=head[u];

    head[u]=e++;

}









void Add(int u,int v,int cap)

{

    add(u,v,cap);

    add(v,u,0);

}









int pre[N],h[N],num[N],cur[N];









int Maxflow(int s,int t,int n)

{

    int i;

    for(i=0;i<=n;i++) h[i]=num[i]=0,cur[i]=head[i];

    int ans=0,u=s,v,x,Min;

    

    while(h[u]<n)

    {

        if(u==t)

        {

            Min=INF+1;

            for(i=s;i!=t;i=edges[cur[i]].v)

            {

                x=cur[i];

                if(edges[x].cap<Min) Min=edges[x].cap,v=i;

            }

            ans+=Min; u=v;

            for(i=s;i!=t;i=edges[cur[i]].v)

            {

                x=cur[i];

                edges[x].cap-=Min;

                edges[x^1].cap+=Min;

            }

        }

        for(i=cur[u];i!=-1;i=edges[i].next)

        {

            v=edges[i].v;

            if(edges[i].cap>0&&h[u]==h[v]+1) break;

        }

        if(i!=-1)

        {

            cur[u]=i;

            pre[edges[i].v]=u;

            u=edges[i].v;

        }

        else

        {

            if(--num[h[u]]==0) break;

            cur[u]=head[u];

            x=n;

            for(i=head[u];i!=-1;i=edges[i].next)

            {

                if(edges[i].cap>0) x=min(x,h[edges[i].v]);

            }

            h[u]=x+1;

            num[x+1]++;

            if(u!=s) u=pre[u];

        }

    }

    return ans;

}









int s,t,n,m,a[N];

















int main()

{

    clr(head,-1);

    RD(n,m);

    s=0; t=n+1;

    int i,x,y;

    FOR1(i,n) 

    {

        RD(a[i]);

        if(a[i]) Add(s,i,1);

        else Add(i,t,1);

    }

    FOR1(i,m)

    {

        RD(x,y);

        if(a[x]==a[y]) continue;

        if(a[x]) Add(x,y,1);

        else Add(y,x,1);

    }

    PR(Maxflow(s,t,t+1));

}