1. 程式人生 > >bzoj4808: 馬 & bzoj3175: [Tjoi2013]攻擊裝置 (黑白染色+最小割)

bzoj4808: 馬 & bzoj3175: [Tjoi2013]攻擊裝置 (黑白染色+最小割)

Go else bzoj targe true 皇後 span 黑白 HP

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 }

bzoj4808: 馬 & bzoj3175: [Tjoi2013]攻擊裝置 (黑白染色+最小割)