【学校OJ】二分图匹配 骑士共存问题

来源:互联网 发布:把网站生成app源码 编辑:程序博客网 时间:2024/05/21 05:39

题目描述

一个N*N的棋盘上,有一些小方格被拿走了,不能放置骑士,其它位置可以放。现要在棋盘上放若干骑士,要求任一个骑士都不能在其他骑士的攻击点上。请算出棋盘上最多能有几个骑士。骑士攻击范围如图所示(S是骑士的位置,X表示马的攻击点) 

输入

第一行包含2个整数n和m,用单个的空格分开,1<=n<=200 , 0<=m < 40000;n 是国际象棋棋盘的大小,m是被拿走的格子数。 下面m行每行包含 2 个整数:x和y,用单个的空格分开,1<=x,y<=n,这些是被拿走的格子的坐标。 棋盘的左上角的坐标是(1,1),右下角是(n,n)。拿走的格子没有重复的。

输出

一个整数,它应该是能放在国际象棋棋盘上的互不攻击对方的马的最大的数量。

样例输入

 (如果复制到控制台无换行,可以先粘贴到文本编辑器,再复制)

3 21 13 3

样例输出

5

    由于没有绑定手机而苦逼了很久,所以为了补偿就来一篇吧。

    二分图呢,就是这样一种图:可以把所有节点分成两个部分,x与y,而所有边必须是x连接到y,不允许x或y中出现自己连接的情况。而由于二分图的这种性质也是定义,就出现了一种问题——二分图的最大匹配。就是求二分图中选出尽可能多的边,让任意两条边不相连。一种通俗的诠释:一群剩男剩女进行组成伴侣,在不同性恋、不一夫多妻、一妻多夫的情况下撮合尽可能多的情侣。

    匈牙利算法就可以解决这种问题。具体操作是这样的:

    1.寻找一个没有匹配的x节点(剩男),然后从它所有有边相连的(互相有感觉的)y节点中寻找一个同样没有匹配的(剩女),这时,将他们加入到匹配里面(撮合成一对),任务完成(撮合成功),再进行一遍1,直到无法进行1为止(没有剩男了~)。如果有边相连的y全部都在匹配中(没有两厢情愿的女孩子是单身),则对每一个相连的y进行2

    2.将这个有边相连的(有男朋友的)y的x(男朋友)进行待定,如果x可以找到除了自己的其他空闲的y(有其他剩女可以选),那么将匹配关系变一变(小三上位,原配另找新欢),就多了一对匹配不是么?但如果同样没有找到怎么办?一样对所有相连的y进行2操作,直到多了一对匹配为止~如果找遍所有人都无法解决问题,很抱歉原来的这位x,你永远没有办法匹配(一辈子单身,惨)了……

    咳咳咳,通过黑色和白色字的讲解,可以大致了解匈牙利算法了。那么来看看这道题吧。

    我们可以显而易见的看出,按国际象棋格子的分法,有黑色和白色之分,可以很容易的发现,马从黑色只能跳到白色,白色只能跳到黑色,也就是处于白色格子的没有自区域的相连,黑的同样没有,符合二分图的性质,而一步可以跳到的地方就相当于有一条边相连。

    有边相连的格点不可以同时放马,所以放了一个马与之相连的所有边就全部被控制。删去最少点使得所有边都不会冲突,这就是最小点覆盖边问题!答案是等于最大匹配的!然后用总数减去最大匹配数即可了!

    当然,有了思路,要想不超时,就看你的代码丑不丑了……

#include<cstdio>#include<algorithm>#include<cstring>using namespace std;int getint(){int p=0,f=0;char c=getchar();while((c<'0'||c>'9')&&c!='-')c=getchar();if(c=='-')f=1,c=getchar();while(c>='0'&&c<='9')p=p*10+c-'0',c=getchar();return f?-p:p;}void putint(int p){if(p<0)putchar('-'),p=-p;if(p>9)putint(p/10);putchar(p%10+'0');}int n,m,sum,cnt[2];bool A[205][205];int num[205][205];int d[8][2]={{2,1},{-2,1},{2,-1},{-2,-1},{1,2},{-1,2},{1,-2},{-1,-2}};int to[20005][10];int CP[20005];bool vis[20005];bool check(int x,int y){if(x<1||y<1||x>n||y>n||A[x][y]||vis[num[x][y]])return 0;return 1;}bool xyl(int x){for(int i=1;i<=to[x][0];i++){int p=to[x][i];if(!vis[p]){vis[p]=1;if(!CP[p]||xyl(CP[p])){CP[p]=x;return 1;}}}return 0;}int main(){n=getint();m=getint();for(int i=1;i<=m;i++){int a=getint(),b=getint();A[a][b]=1;}for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(!A[i][j])num[i][j]=++cnt[(i+j)%2];for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(!A[i][j]&&(i+j)%2==0)for(int k=0;k<8;k++)if(check(i+d[k][0],j+d[k][1]))to[num[i][j]][++to[num[i][j]][0]]=num[i+d[k][0]][j+d[k][1]];for(int i=1;i<=cnt[0];i++){sum+=xyl(i);memset(vis,0,sizeof(vis));}putint(cnt[1]+cnt[0]-sum);}


0 0
原创粉丝点击