bzoj4808: 马 & bzoj3175: [Tjoi2013]攻击装置 (黑白染色+最小割)

bzoj4808: 马 & bzoj3175: [Tjoi2013]攻击装置

题目:传送门

简要题意:

   和n皇后问题差不多,但是这里是每个棋子走日子,而且有些格子不能放棋子。求最多能放多少个棋子。

 


 

 

题解:

   双倍经验好评

   之前看过机房神犇做...有点印象是最小割。

   但是直接割的话不会...要应用到黑白染色:

   最开始我想递归染色,也就是取一个开始染,然后递归下去...

   波老师说会错ORZ...因为感觉递归的情况不好掌握,有可能会重复染色...

   结果有一个肥肠巧妙的方法...直接相邻的染为不同颜色

   之后就会惊奇的发现,woc当前格子能跳到的格子一定是和自己异色的!

   那就最小割咯

   st连白的,黑的连ed,互相能到达的黑色和白色连inf

 

 


 

 

代码:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cstdlib>
  4 #include<cmath>
  5 #include<algorithm>
  6 #define inf 999999999
  7 using namespace std;
  8 struct node
  9 {
 10     int x,y,c,next,other;
 11 }a[1110000];int len,last[410000];
 12 void ins(int x,int y,int c)
 13 {
 14     int k1,k2;
 15     k1=++len;
 16     a[len].x=x;a[len].y=y;a[len].c=c;
 17     a[len].next=last[x];last[x]=len;
 18      
 19     k2=++len;
 20     a[len].x=y;a[len].y=x;a[len].c=0;
 21     a[len].next=last[y];last[y]=len;
 22      
 23     a[k1].other=k2;
 24     a[k2].other=k1;
 25 }
 26 int st,ed,head,tail,n,m;
 27 int list[410000],h[410000];
 28 bool bt_h()
 29 {
 30     memset(h,0,sizeof(h));h[st]=1;
 31     list[1]=st;head=1;tail=2;
 32     while(head!=tail)
 33     {
 34         int x=list[head];
 35         for(int k=last[x];k;k=a[k].next)
 36         {
 37             int y=a[k].y;
 38             if(!h[y] && a[k].c)
 39             {
 40                 h[y]=h[x]+1;
 41                 list[tail++]=y;
 42             }
 43         }
 44         head++;
 45     }
 46     if(h[ed])return true;
 47     return false;
 48 }
 49 int find_flow(int x,int flow)
 50 {
 51     int s=0,t;
 52     if(x==ed)return flow;
 53     for(int k=last[x];k;k=a[k].next)
 54     {
 55         int y=a[k].y;
 56         if(h[y]==h[x]+1 && a[k].c && s<flow)
 57         {
 58             s+=t=find_flow(y,min(a[k].c,flow-s));
 59             a[k].c-=t;a[a[k].other].c+=t;
 60         }
 61     }
 62     if(!s)h[x]=0;
 63     return s;
 64 }
 65 int mp[210][210],d[210][210];
 66 bool f[210][210];
 67 const int dx[9]={0,1,1,-1,-1,-2,-2,2,2};
 68 const int dy[9]={0,2,-2,2,-2,-1,1,-1,1};
 69 int main()
 70 {
 71     scanf("%d%d",&n,&m);int s=0,sum=0;
 72     for(int i=1;i<=n;i++)
 73         for(int j=1;j<=m;j++)
 74         {
 75             scanf("%d",&mp[i][j]),d[i][j]=++s;
 76             if(mp[i][j]!=1)sum++;
 77         }
 78     st=n*m+1;ed=st+1;
 79     memset(f,0,sizeof(f));
 80     for(int i=1;i<=n;i++)
 81     {
 82         for(int j=1;j<=m;j++)
 83         {
 84             if(i==1 && j==1)f[i][j]=1;
 85             else if(i!=1 && j==1)
 86             {
 87                 if(f[i][j]==f[i-1][j])
 88                 f[i][j]^=1;
 89             }
 90             else
 91             {
 92                 if(f[i][j]==f[i][j-1])
 93                 f[i][j]^=1;
 94             }
 95         }
 96     }
 97     for(int i=1;i<=n;i++)
 98         for(int j=1;j<=m;j++)
 99         {
100             if(mp[i][j]!=1)
101             {
102                 if(f[i][j])ins(st,d[i][j],1);
103                 else ins(d[i][j],ed,1);
104             }
105         }
106     for(int i=1;i<=n;i++)
107         for(int j=1;j<=m;j++)
108             if(mp[i][j]!=1 && f[i][j])
109                 for(int k=1;k<=8;k++)
110                 {
111                     int ii=i+dx[k],jj=j+dy[k];
112                     if(ii>=1 && ii<=n && jj>=1 && jj<=m)
113                         if(mp[ii][jj]!=1)
114                             if(!f[ii][jj])
115                                 ins(d[i][j],d[ii][jj],inf);
116                 }
117     int ans=0;
118     while(bt_h())ans+=find_flow(st,inf);
119     printf("%d\n",sum-ans);
120     return 0;
121 }

 

posted @ 2018-03-21 08:37  CHerish_OI  阅读(181)  评论(0编辑  收藏  举报