bzoj2150: 部落战争(匈牙利)
2150: 部落战争
题目:传送门
题解:
辣鸡数据..毁我AC率
先说做法,很容易就可以看出是二分图匹配的最小路径覆盖(可能是之前不久刚做过类似的题)
一开始还傻逼逼的去直接连边然后准备跑floyd...肯定是做祭祀做傻了
二分图嘛,将每个点拆成两个集合再连啊...
然后最小路径覆盖=总点数-最大匹配数
强烈吐槽!个人习惯用数组存点编号...50*50的数据范围我开55*55...结果WA n次
然后...改成56*56...AC。。。ORZ
代码:
1 #include<cstdio> 2 #include<cstring> 3 #include<cstdlib> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 struct node 8 { 9 int x,y,next; 10 }a[25000];int len,last[25000]; 11 void ins(int x,int y) 12 { 13 len++;a[len].x=x;a[len].y=y; 14 a[len].next=last[x];last[x]=len; 15 } 16 char s[55][55]; 17 int n,m,R,C,t; 18 int match[25000],chw[25000]; 19 bool findmuniu(int x) 20 { 21 for(int k=last[x];k;k=a[k].next) 22 { 23 int y=a[k].y; 24 if(chw[y]!=t) 25 { 26 chw[y]=t; 27 if(match[y]==0 || findmuniu(match[y])) 28 { 29 match[y]=x; 30 return true; 31 } 32 } 33 } 34 return false; 35 } 36 int d[56][56];//辣鸡数据 37 int main() 38 { 39 scanf("%d%d%d%d",&n,&m,&R,&C); 40 for(int i=1;i<=n;i++)scanf("%s",s[i]+1); 41 int ss=0;memset(d,-1,sizeof(d)); 42 for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)d[i][j]=++ss; 43 const int dx[5]={0,R,R,C,C}; 44 const int dy[5]={0,-C,C,-R,R}; 45 int sum=0;len=0;memset(last,0,sizeof(last)); 46 for(int i=1;i<=n;i++) 47 for(int j=1;j<=m;j++) 48 if(s[i][j]=='.') 49 { 50 sum++; 51 for(int k=1;k<=4;k++) 52 { 53 int x=i+dx[k],y=j+dy[k]; 54 if(d[x][y]!=-1 && s[x][y]!='x') 55 ins(d[i][j],d[x][y]+n*m); 56 } 57 } 58 memset(match,0,sizeof(match)); 59 memset(chw,0,sizeof(chw)); 60 int ans=0; 61 for(int i=1;i<=n;i++) 62 for(int j=1;j<=m;j++) 63 if(s[i][j]=='.') 64 { 65 t++; 66 if(findmuniu(d[i][j]))ans++; 67 } 68 printf("%d\n",sum-ans); 69 return 0; 70 }