NKOJ 4042 (CQOI 2017) 老C的方块(最小割+染色)

来源:互联网 发布:淘宝上亚马逊会员代买 编辑:程序博客网 时间:2024/05/19 04:27

P4042老C的方块

问题描述
这里写图片描述
这里写图片描述
这里写图片描述
这里写图片描述


此题比较明显可以想到图论,由于是经典的棋盘问题,我们观察四种讨厌的形状,发现这四种形状有一个共同特点,即都可以看成以特殊边为邻边的两个方块各自再连上一个方块,然后我们发现,特殊边的分布刚好是配合这个规律的,于是我们将棋盘染色
这里写图片描述
染色很丑陋,因为是我故意的。
简单说一下,我们将格子分成4类,分别是四种颜色,我们发现,如果一个图形是讨厌的,那么一定满足这个图形是黄-黑-白-蓝,或者黄-白-黑-蓝,于是构图的方法也就出来了
我们新建一个源点S,和一个汇点T。
从S出发连到黄色格子,容量是他的费用。
从黄色格子连到他所相邻的黑色和白色格子,容量无穷大。
相邻黑白格子之间连双向边,容量是黑白格子中费用较小的一个。
从黑白格子出发,连到相邻的蓝色格子,容量无穷大。
从蓝色格子出发,连到汇点T。
最后求出上图的最小割即可。

附上代码:

#include<stdio.h>#include<iostream>#include<algorithm>#include<cstring>#include<map>#define ll long long#define N 4234567using namespace std;struct node{ll xi,yi,wi,id;};const ll ct=1000000LL;ll S,T,C,R,n;map<ll,node>Q;node P[N];ll TOT=1,NE[N],EN[N],G[N],LA[N],dis[N],cnt[N];void ADD(ll x,ll y,ll z){    TOT++;    EN[TOT]=y;    G[TOT]=z;    NE[TOT]=LA[x];    LA[x]=TOT;}void A1(ll k){    ll t;node tmp;    ADD(S,k,P[k].wi);ADD(k,S,0);    t=P[k].xi*ct+ct+P[k].yi;    if(Q.count(t))    {        tmp=Q[t];        ADD(k,tmp.id,1e18);        ADD(tmp.id,k,0);    }    t-=2*ct;    if(Q.count(t))    {        tmp=Q[t];        ADD(k,tmp.id,1e18);        ADD(tmp.id,k,0);    }    if(P[k].xi&1)    {        t=P[k].xi*ct+P[k].yi+1;        if(Q.count(t))        {            tmp=Q[t];            ADD(k,tmp.id,1e18);            ADD(tmp.id,k,0);        }    }    else    {        t=P[k].xi*ct+P[k].yi-1;        if(Q.count(t))        {            tmp=Q[t];            ADD(k,tmp.id,1e18);            ADD(tmp.id,k,0);        }    }}void A2(ll k){    ll t;node tmp;    t=P[k].xi*ct+P[k].yi+1;    if(Q.count(t))    {        tmp=Q[t];        ADD(k,tmp.id,min(P[k].wi,tmp.wi));        ADD(tmp.id,k,0);        ADD(tmp.id,k,min(P[k].wi,tmp.wi));        ADD(k,tmp.id,0);    }}void A3(ll k){    ll t;node tmp;    ADD(k,T,P[k].wi);ADD(T,k,0);    t=P[k].xi*ct+ct+P[k].yi;    if(Q.count(t))    {        tmp=Q[t];        ADD(tmp.id,k,1e18);        ADD(k,tmp.id,0);    }    t-=2*ct;    if(Q.count(t))    {        tmp=Q[t];        ADD(tmp.id,k,1e18);        ADD(k,tmp.id,0);    }    if(!(P[k].xi&1))    {        t=P[k].xi*ct+P[k].yi+1;        if(Q.count(t))        {            tmp=Q[t];            ADD(tmp.id,k,1e18);            ADD(k,tmp.id,0);        }    }    else    {        t=P[k].xi*ct+P[k].yi-1;        if(Q.count(t))        {            tmp=Q[t];            ADD(tmp.id,k,1e18);            ADD(k,tmp.id,0);        }    }}ll tp(ll x,ll y){    ll p=y&3;    if(x&1)return p+1;    if(p==0)return 3;    if(p==1)return 1;    if(p==2)return 4;    if(p==3)return 2;}void edge(){    ll i,t;    for(i=1;i<=n;i++)    {        t=tp(P[i].xi,P[i].yi);        if(t==1)A1(i);        if(t==2)A2(i);        if(t==4)A3(i);    }}ll SAP(ll u,ll f){    ll i,v,d=0,tmp;    if(u==T)return f;    for(i=LA[u];i>1;i=NE[i])    {        v=EN[i];        if(G[i]&&dis[u]==dis[v]+1)        {            tmp=SAP(v,min(f-d,G[i]));            G[i]-=tmp;            G[i^1]+=tmp;            d+=tmp;            if(f==d||dis[S]>=n+2)return d;        }    }    if(!--cnt[dis[u]])dis[S]=n+2;    cnt[++dis[u]]++;    return d;}int main(){    ll i,x,y,w,ans=0;node tmp;    scanf("%lld%lld%lld",&C,&R,&n);    for(i=1;i<=n;i++)    {        scanf("%lld%lld%lld",&y,&x,&w);        tmp.id=i;tmp.wi=w;        P[i].xi=x;P[i].yi=y;P[i].wi=w;P[i].id=i;        Q[x*ct+y]=tmp;    }    S=n+1;T=S+1;edge();    while(dis[S]<n+2)ans+=SAP(S,1e18);    cout<<ans;}
原创粉丝点击