4554: [Tjoi2016&Heoi2016]游戏
题目:传送门
题解:
一道很牛逼的匈牙利。。和之前模拟赛的一道题有点相似(不过这题不用完美匹配)
我们可以把连续的行和列全部编号(如果之间没有#就归为同一编号)
很容易就可以证明,编号后的行和列只能匹配一次,跑一下找母牛就ok(数组开小的我没有一A很难受)
强烈吐槽:数据开头和结尾的字符串不用输入(cnmmmmmmmm!!!!)
但是做完这题还是很兴奋的,哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈终于超过苏大佬了哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈
代码:
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[5100];int len,last[5100]; 11 void ins(int x,int y) 12 { 13 len++; 14 a[len].x=x;a[len].y=y; 15 a[len].next=last[x];last[x]=len; 16 } 17 int match[5100],chw[5100],t; 18 int find_muniu(int x) 19 { 20 for(int k=last[x];k;k=a[k].next) 21 { 22 int y=a[k].y; 23 if(chw[y]!=t) 24 { 25 chw[y]=t; 26 if(match[y]==0 || find_muniu(match[y])) 27 { 28 match[y]=x; 29 return true; 30 } 31 } 32 } 33 return false; 34 } 35 char st[55][55],s[5]; 36 int belong1[55][55],belong2[55][55]; 37 int n,m; 38 int main() 39 { 40 freopen("ans.in","r",stdin); 41 freopen("ans.out","w",stdout); 42 //scanf("%s",s+1); 43 scanf("%d%d",&n,&m); 44 for(int i=1;i<=n;i++)scanf("%s",st[i]+1); 45 //scanf("%s",s+1); 46 int H=0,L=0; 47 for(int i=1;i<=n;i++) 48 { 49 H++;int k=1; 50 while(st[i][k]!='*' && k<=m)k++; 51 for(int j=k;j<=m;j++) 52 { 53 if(st[i][j]=='#')H++; 54 if(st[i][j]=='*')belong1[i][j]=H; 55 } 56 } 57 L=H; 58 for(int j=1;j<=m;j++) 59 { 60 L++;int k=1; 61 while(st[k][j]!='*' && k<=n)k++; 62 for(int i=k;i<=n;i++) 63 { 64 if(st[i][j]=='#')L++; 65 if(st[i][j]=='*')belong2[i][j]=L; 66 } 67 } 68 for(int i=1;i<=n;i++) 69 for(int j=1;j<=m;j++) 70 if(st[i][j]=='*') 71 ins(belong1[i][j],belong2[i][j]); 72 memset(chw,0,sizeof(chw));memset(match,0,sizeof(match)); 73 int ans=0; 74 for(int i=1;i<=H;i++) 75 { 76 t=i;if(find_muniu(i))ans++; 77 } 78 printf("%d ",ans); 79 return 0; 80 }