注意到这是一个经典的二分图问题,我们按照套路将图进行奇偶染色,注意边界条件的判断。
一定要注意的问题是数组的大小,不要看到n=100就开成100,一共有n^2个点,所以数组和最后的答案统计范围都是n^2
#include<bits/stdc++.h>
using namespace std;
const int maxx=2000000;
int vis[20000];
struct node{
int to;
int next;
}e[maxx];
int head[maxx],match[20000];
int k;
void add(int u,int v){
e[++k].to=v;
e[k].next=head[u];
head[u]=k;
}
int n,m;
int dfs(int u){
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(!vis[v]){
vis[v]=1;
if(!match[v] || dfs(match[v])==1){
match[v]=u;
match[u]=v;
return 1;
}
}
}
return 0;
}
int sum;
int a[210][210];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int x,y;
scanf("%d%d",&x,&y);
a[x][y]=1;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(a[i][j]) continue;
int pos=(i-1)*n+j;
if(!a[i][j-1] && j>=2){
add(pos,pos-1);
}
if(!a[i][j+1] && j<n){
add(pos,pos+1);
}
if(!a[i-1][j] && i>1){
add(pos,pos-n);
}
if(!a[i+1][j] && i<n){
add(pos,pos+n);
}
}
}
for(int i=1;i<=n*n;i++){
if(!match[i]){
if(dfs(i)==1) sum++;
memset(vis,0,sizeof(vis));
}
}
printf("%d\n",sum);
}
请问数组为什么要开20000 而不是10000呢?这也不是双向边啊,我开10000的话就会有几组数据比标准答案小一,调了半天看您的题解蜜汁搞不懂为啥数组开这么大。希望楼主解答^_^ ,谢谢~
你开10005试试
大佬能问你一个问题吗?
这个地方为什么要写2个,
match[v]=u;
match[u]=v;
请问这样写的原理是什么呢?(疑惑)
存一个方向也是可以的,可以参考这份代码AcWing 372. 棋盘覆盖
谢谢y总,
搞定了,hhh
这样写的原理是:
这个匈牙利算法是一个匹配的过程,我们可以举一个不恰当的例子,我们要寻找最大匹配,我们每次去找单身的男生,那么这个男生就会去找他所喜欢的女生(可能有很多),然后女生单身,或者女生的男朋友可以换一个女朋友,那么就配对成功。我们将左子集与右子集互相匹配。这个题目中,我们采取对方格奇偶染色的方式进行二分图的构图,那么一个点不在左子集就在右子集,我们在找到一个匹配之后,我们记录下他们已经匹配成功,一方面是为了下面n*n的循环中出错,而是在dfs中不出错。如果不记录两个,那么在dfs的时候,我们去找喜欢的女生的男朋友时就无法递归下去了。