2022/2/10
2022/2/10
P5030 长脖子鹿放置
网络流求二分图最大匹配
画几个点会发现行号奇偶性不同的不会相互攻击
那么将点按行号奇偶性进行划分。
分成的两部分做二分图最大匹配
二分图最大独立集=点数-二分图最大匹配
那么答案就是 n*m-cnt-二分图最大匹配
参考代码
#include<bits/stdc++.h>
#define ll long long
#define pii pair<long long , long long >
#define si size()
#define fi first
#define se second
#define pb push_back
#define int long long
using namespace std;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(ll x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}
const ll mod=1e9+7;
const ll inf=0x3f3f3f3f;
const int qs=1e6+7;
int a[207][207],n,m;
int s,t,dis[qs],head[qs],nxt[qs],to[qs],p;
int mv[8][2]={{1,3},{1,-3},{3,1},{3,-1},{-1,3},{-1,-3},{-3,1},{-3,-1}};
void add(int fx,int tx,ll dx){
to[p]=tx; dis[p]=dx; nxt[p]=head[fx]; head[fx]=p++;
//反向边
// cout<<"fx="<<fx<<" tx="<<tx<<"\n";
to[p]=fx; dis[p]=0; nxt[p]=head[tx]; head[tx]=p++;
}
void build_map(){
s=0;t=n*m+1;
for(int i=1;i<=n;++i){
for(int j=1;j<=m;++j){
if(a[i][j]) continue;
int fx=m*(i-1)+j;
if(i&1){
add(s,fx,1);
for(int k=0;k<8;++k){
int x=i+mv[k][0],y=j+mv[k][1];
// cout<<"i="<<i<<" j="<<j<<" x="<<x<<" y="<<y<<"\n";
if(x<1||x>n||y<1||y>m||a[x][y]) continue;
int fy=m*(x-1)+y;
add(fx,fy,1);
}
}
else add(fx,t,1);
}
}
}
//Dinic
ll level[qs],cur[qs];
//level是各点到终点的深度,cur为当前弧优化的增广起点
bool bfs(){//分层图
memset(level,-1,sizeof(level));
level[s]=0;
memcpy(cur,head,sizeof(head));
cur[s]=head[s];
queue<int> Q;
Q.push(s);
while(Q.si){
int k=Q.front();
Q.pop();
for(int i=head[k];i!=-1;i=nxt[i]){
if(dis[i]>0&&level[to[i]]==-1){
level[to[i]]=level[k]+1;
Q.push(to[i]);
if(to[i]==t) return true;
}
}
}
return false;
}
ll dfs(int u,ll flow){
if(u==t) return flow;
ll ret=flow; //剩余的流量
for(int i=cur[u];i!=-1&&ret>0;i=nxt[i]){
cur[u]=i;// 当前弧优化
//如果还能流下去 并且 更深
if(dis[i]>0&&level[to[i]]==level[u]+1){
ll c=dfs(to[i],min(dis[i],ret));
if(!c) level[to[i]]=-1; //剪枝,出去增广完毕的点
ret-=c; //剩余的水流被用了c
dis[i]-=c; //减权重
dis[i^1]+=c; //反向边加权重
}
}
return flow-ret;//返回用掉的水流
}
//END
signed main(){
memset(head,-1,sizeof(head));
int fk;
n=read(),m=read(),fk=read();
int x,y;
int cnt=0;
for(int i=1;i<=fk;++i){
x=read(),y=read();
if(a[x][y]) continue;
cnt++;
a[x][y]=1;
}
build_map();
ll ans=n*m-cnt;
while(bfs()){
ans-=dfs(s,inf);
}
cout<<ans<<"\n";
}
/*
*/