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;
}

 

posted @ 2018-12-22 19:45  Zinn  阅读(153)  评论(0编辑  收藏  举报