P4042老C的方块
此题比较明显可以想到图论,由于是经典的棋盘问题,我们观察四种讨厌的形状,发现这四种形状有一个共同特点,即都可以看成以特殊边为邻边的两个方块各自再连上一个方块,然后我们发现,特殊边的分布刚好是配合这个规律的,于是我们将棋盘染色
染色很丑陋,因为是我故意的。
简单说一下,我们将格子分成4类,分别是四种颜色,我们发现,如果一个图形是讨厌的,那么一定满足这个图形是黄-黑-白-蓝,或者黄-白-黑-蓝,于是构图的方法也就出来了
我们新建一个源点S,和一个汇点T。
从S出发连到黄色格子,容量是他的费用。
从黄色格子连到他所相邻的黑色和白色格子,容量无穷大。
相邻黑白格子之间连双向边,容量是黑白格子中费用较小的一个。
从黑白格子出发,连到相邻的蓝色格子,容量无穷大。
从蓝色格子出发,连到汇点T。
最后求出上图的最小割即可。
附上代码:
#include
#include
#include
#include
#include
#define ll long long
#define N 4234567
using namespace std;
struct node{ll xi,yi,wi,id;};
const ll ct=1000000LL;
ll S,T,C,R,n;
mapQ;
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]2)ans+=SAP(S,1e18);
cout<;
}