题目链接:https://www.luogu.com.cn/problem/P5030
提示:二分图最大独立集=点数-最小点覆盖(最大匹配)
题解:这个题其实想想的话可以知道,应该把一些互吃边连在一起建边,把n*n的图划分成一个个的点并标号,有些是陷阱点,所以不用和他进行建边。这样我们能看出来是一个求最大独立集的问题(即二分图相邻2点不连的话最大可包括几个点)。想到了就还挺容易的吧。关于建边其实可以有优化(没有优化也可以过但是浪费时间)。因为我们看到其实其实行是奇数的话,其互吃点必在偶数行,所以可以进一步简化到奇偶边建边(可以省去一半的建边)。而且对于同排多点建边其实你用一个add就可以了,没必要2个add最后除2,亲测有效。
AC100分代码(记得一开始的:不保证禁止放置的格子互不相同。需要去重):
#include<bits/stdc++.h> #define ll long long #define rep(i,a,n) for(int i=a;i<=n;i++) #define per(i,n,a) for(int i=n;i>=a;i--) #define endl ' ' #define eps 0.000000001 #define pb push_back #define mem(a,b) memset(a,b,sizeof(a)) #define IO ios::sync_with_stdio(false);cin.tie(0); using namespace std; const int INF=0x3f3f3f3f; const ll inf=0x3f3f3f3f3f3f3f3f; const int mod=1e9+7; const int maxn=1e5+5; int tot,head[maxn]; struct E{ int to,next; }edge[1000005]; void add(int u,int v){ edge[tot].to=v; edge[tot].next=head[u]; head[u]=tot++; } int n,m,k,cnt,used[200*200+5],match[200*200+5]; int find(int x){ for(int i=head[x];i!=-1;i=edge[i].next){ int v=edge[i].to; if(!used[v]){ used[v]=true; if(!match[v]||find(match[v])){ match[v]=x; return true; } } } return false; } int a[305][305]; int dx[8]={-3,3,-3,3,-1,1,-1,1}; int dy[8]={1,1,-1,-1,3,3,-3,-3}; int f(int x,int y){ return (x-1)*m+y; } int main(){ cin>>n>>m>>k;mem(head,-1); int cnt=0; rep(i,1,k){ int x,y;cin>>x>>y; if(!a[x][y]){ a[x][y]=1;++cnt; } } rep(i,1,n){ rep(j,1,m){ if(!a[i][j]&&i%2==0){ rep(k,0,7){ int x=i+dx[k],y=j+dy[k]; if(x>0&&x<=n&&y>0&&y<=m&&!a[x][y]){ add(f(i,j),f(x,y)); } } } } } int ans=0; rep(i,1,f(n,m)){ mem(used,0); if(find(i)) ans+=1; } cout<<n*m-ans-cnt<<endl; } /* 8 7 5 1 1 5 4 2 3 4 7 8 3 */