CF387D George and Interesting Graph

link

一道构造题,验证的过程用到了网络流。

数据范围不大,考虑枚举中心点是谁,然后就考虑暴力补齐中心点和周围点的边,补齐过程扫描一遍统计边数即可,注意需要的边数是 \(2m-1\) ,导致我卡了一会。然后对于周围的点,由于每个点已经被强制夺去了一个出度和一个入度,那么每个点就还需要一个出边和一个入边。这就是二分图匹配的板子,匹配出最大答案之后砍掉剩下的无用边再补齐那些可怜的小家伙即可。既然大家都用网络流写的二分图最大匹配那我也就这么写了,虽然应该用裸的二分图匹配也不会超时。注意多组数据之间的初始化问题,我是傻逼调了两天最后发现esum赋值为0了。大乌鱼,好大的乌鱼。

code

#include<bits/stdc++.h>
//#define feyn
const int N=2010;
const int M=5000010;
const int maxn=1e9;
using namespace std;
inline void read(int &wh){
	wh=0;int f=1;char w=getchar();
	while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
	while(w>='0'&&w<='9'){wh=wh*10+w-'0';w=getchar();}
	wh*=f;return;
}

struct node{int a,b;}a[N];//初始边
int m,n,ans=1e9; 

int sa[N],sb[N],ss,tt,cnt;
struct edge{
	int t,v,next;
}e[M];
int head[N],esum=1;
inline void adde(int fr,int to,int val){
	e[++esum]=(edge){to,val,head[fr]};head[fr]=esum;
}
inline void add(int fr,int to,int val){
	adde(fr,to,val);adde(to,fr,0);
}
int nt,t[N],d[N],q[N],ll,rr;
inline bool check(){
	nt++;t[q[ll=rr=1]=ss]=nt;d[ss]=1;
	while(ll<=rr){
		int wh=q[ll++];
		for(int i=head[wh],th;i;i=e[i].next){
			if(e[i].v==0||t[th=e[i].t]==nt)continue;
			d[th]=d[wh]+1;t[th]=nt;q[++rr]=th;
		}
	}
	return t[tt]==nt;
}
inline int dinic(int wh,int val){
	if(wh==tt)return val;
	int used=0;
	for(int i=head[wh],th;i;i=e[i].next){
		if(e[i].v==0||d[th=e[i].t]!=d[wh]+1)continue;
		int now=dinic(th,min(val,e[i].v));
		if(now)used+=now,val-=now,e[i].v-=now,e[i^1].v+=now;
		if(val==0)break;
	}
	if(val)d[wh]=-1;return used;
}
 
void solve(int wh){//以wh为中心的答案
	memset(head,0,sizeof(head));
	esum=cnt=0;
	
	int an=0,num=0,aa=0;
	for(int i=1;i<=n;i++)num+=a[i].a==wh||a[i].b==wh;
	an+=m*2-num-1;
	num=0;ss=++cnt,tt=++cnt;
	for(int i=1;i<=m;i++){
		sa[i]=++cnt;sb[i]=++cnt;
		add(ss,sa[i],1);add(sb[i],tt,1);
	}
	for(int i=1;i<=n;i++){
		if(a[i].a==wh||a[i].b==wh)continue;
		num++;add(sa[a[i].a],sb[a[i].b],1);
	}
	while(check())aa+=dinic(ss,maxn);
	an+=num-aa;//应该删掉的边
	an+=(m-1)-aa;//应该加上的边
	if(an<ans)ans=an;return; 
}

signed main(){
	
	#ifdef feyn
	freopen("in.txt","r",stdin);
	#endif
	
	read(m);read(n);
	for(int i=1;i<=n;i++){
		read(a[i].a);read(a[i].b);
	}
	for(int i=1;i<=m;i++)solve(i);
	printf("%d",ans);
	
	return 0;
}
posted @ 2022-07-14 15:56  Feyn618  阅读(23)  评论(0编辑  收藏  举报