bzoj 4823 & 洛谷 P3756 老C的方块 —— 最小割
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4823
https://www.luogu.org/problemnew/show/P3756
巧妙建图;
其实“俄罗斯方块”就是选择一条特殊边两边的方格,左右两边周围的六个中再各选两个;
于是可以把图“四分”,特殊边两边的格子算两种,而且奇数行和偶数行恰好相反,然后两边围着的格子也算两种;
然后不能有上面四种可选方格同时存在的情况,建出图来跑最小割即可。
代码如下:
#include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<queue> using namespace std; int const xn=2e5+5,xm=2e6+5,inf=1e9; int C,R,n,hd[xn],ct=1,to[xm],nxt[xm],c[xm],dis[xn],cur[xn],S,T; map<int,int>mp[xn]; struct N{int x,y;}p[xn]; queue<int>q; int rd() { int ret=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();} while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar(); return f?ret:-ret; } void ade(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct; c[ct]=z;} void add(int x,int y,int z){ade(x,y,z); ade(y,x,0);} int tp(int x,int y) { int d=y%4; if(x&1){if(d==1)return 1; if(d==2)return 2; if(d==3)return 4; if(!d)return 3;} else {if(d==1)return 3; if(d==2)return 4; if(d==3)return 2; if(!d)return 1;} } void addedge(int a,int b,int x,int y) { if(a==3&&b==1)add(n+x,y,inf); else if(a==1&&b==2)add(n+x,y,inf); else if(a==2&&b==4)add(n+x,y,inf); } bool bfs() { for(int i=S;i<=T;i++)dis[i]=0; dis[S]=1; q.push(S); while(q.size()) { int x=q.front(); q.pop(); for(int i=hd[x],u;i;i=nxt[i]) if(!dis[u=to[i]]&&c[i])dis[u]=dis[x]+1,q.push(u); } return dis[T]; } int dfs(int x,int fl) { //printf("x=%d fl=%d\n",x,fl); if(x==T)return fl; int ret=0; for(int &i=cur[x],u;i;i=nxt[i]) { if(dis[u=to[i]]!=dis[x]+1||!c[i])continue; int tmp=dfs(u,min(fl-ret,c[i])); if(!tmp)dis[u]=0; c[i]-=tmp; c[i^1]+=tmp; ret+=tmp; if(ret==fl)break; } return ret; } int main() { C=rd(); R=rd(); n=rd(); S=0; T=2*n+1; for(int i=1,x,y,w;i<=n;i++) { y=p[i].y=rd(); x=p[i].x=rd(); w=rd(); mp[x][y]=i; add(i,n+i,w); int t=tp(p[i].x,p[i].y); if(t==3)add(S,i,inf); if(t==4)add(n+i,T,inf); } for(int i=1;i<=n;i++) { int x=p[i].x,y=p[i].y,t=tp(x,y); if(x>1&&mp[x-1][y]){int tt=tp(x-1,y); addedge(t,tt,i,mp[x-1][y]);} if(y>1&&mp[x][y-1]){int tt=tp(x,y-1); addedge(t,tt,i,mp[x][y-1]);} if(x<R&&mp[x+1][y]){int tt=tp(x+1,y); addedge(t,tt,i,mp[x+1][y]);} if(y<C&&mp[x][y+1]){int tt=tp(x,y+1); addedge(t,tt,i,mp[x][y+1]);} } int ans=0; while(bfs()) { memcpy(cur,hd,sizeof hd); ans+=dfs(S,inf); } printf("%d\n",ans); return 0; }