18.10.04模拟赛T2。
毒瘤出题人zzk祭出二分图匹配,然而zwz还是A了......
事实证明zwz大佬是卡不住的。
首先如果每个点都放一个军队的话,总数就是城镇的个数。
但是这样的话就会很浪费。
从上到下,所有可转移的点之间连边,但是这道题要求每个点只能走一次,怎么办呢?
每个点只能走一次,每个人只能有一个对象,这不就是二分图吗(原谅我对二分图的猥琐见解)。
接下来就让那些点乱搞对象匹配(原谅我对匈牙利算法的猥琐见解)(原谅我的变量名cp)。
每有一个匹配,就节省一支军队。
最后就用总数减去匹配数就好了。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int m,n,r,c; 7 int d[55][55]; 8 int cp[2505],vis[2505]; 9 int dx[10],dy[10]; 10 int hd[2505],to[10005],nx[10005],ec; 11 int tot,ans; 12 13 int id(int x,int y) 14 { 15 return n*(x-1)+y; 16 } 17 18 void edge(int af,int at) 19 { 20 to[++ec]=at; 21 nx[ec]=hd[af]; 22 hd[af]=ec; 23 } 24 25 void add(int x,int y) 26 { 27 for(int i=1;i<=4;i++) 28 { 29 int tx=x+dx[i],ty=y+dy[i]; 30 if(tx<=0||tx>m||ty<=0||ty>n)continue; 31 if(!d[tx][ty]) 32 edge(id(tx,ty),id(x,y)); 33 } 34 } 35 36 int ex(int p) 37 { 38 for(int i=hd[p];i;i=nx[i]) 39 { 40 int des=to[i]; 41 if(vis[des]!=tot) 42 { 43 vis[des]=tot; 44 if(!cp[des]||ex(cp[des])) 45 { 46 cp[des]=p; 47 return 1; 48 } 49 } 50 } 51 return 0; 52 } 53 54 void hungary() 55 { 56 for(int i=1;i<=m;i++) 57 { 58 for(int j=1;j<=n;j++) 59 { 60 if(d[i][j])continue; 61 tot++; 62 if(ex(id(i,j)))ans++; 63 } 64 } 65 } 66 67 int main() 68 { 69 scanf("%d%d%d%d",&m,&n,&r,&c); 70 dx[1]=dx[2]=-c,dx[3]=dx[4]=-r; 71 dy[1]=r,dy[2]=-r,dy[3]=c,dy[4]=-c; 72 for(int i=1;i<=m;i++) 73 { 74 char tmp[55]; 75 scanf("%s",tmp+1); 76 for(int j=1;j<=n;j++) 77 { 78 if(tmp[j]=='x')d[i][j]=1; 79 else add(i,j); 80 } 81 } 82 hungary(); 83 printf("%d ",tot-ans); 84 return 0; 85 }