【CF387D】George and Interesting Graph(二分图最大匹配)
题意:给定一张n点m边没有重边的有向图,定义一个有趣图为:存在一个中心点满足以下性质:
1、除了这个中心点之外其他的点都要满足存在两个出度和两个入度。
2、中心 u 需要对任意顶点 v(包括自己)有一条(u,v)的边和(v,u)的边,即他们都要互通。
现在可以删除和添加边,使得给出的原图满足以上情况。询问删除和添加的最小操作次数。
n<=500,m<=1000
思路:枚举中心u,将边分为不相同的三部分:
1.u的自环,记为cir=(0..1)
2.u的出边或入边,记为out与in
3.与u无关的边
存在以下性质:原图删去中心以及1,2类边后每个点的出度与入度都为1
相当于一个点裂成了一个出点与入点,对这些点与边跑二分图最大匹配
考虑答案也有三部分组成:
1.原图中无用的边,即m-in-out-cir-maxmatch
2.需要添加的与中心无关的边,即n-1-maxmatch
3.需要添加的与中心相关的边,即2*(n-1)-in-out+1-cir
三部分加起来即为所求
1 #include<cstdio> 2 #include<cstring> 3 #include<string> 4 #include<cmath> 5 #include<iostream> 6 #include<algorithm> 7 #include<map> 8 #include<set> 9 #include<queue> 10 #include<vector> 11 using namespace std; 12 typedef long long ll; 13 typedef unsigned int uint; 14 typedef unsigned long long ull; 15 typedef pair<int,int> PII; 16 typedef vector<int> VI; 17 #define fi first 18 #define se second 19 #define MP make_pair 20 #define N 1100 21 #define M 1100 22 #define eps 1e-8 23 #define pi acos(-1) 24 #define oo 1e9 25 26 int head[N],vet[N],nxt[N],match[N],flag[N],x[N],y[N],n,m,tot; 27 28 int add(int a,int b) 29 { 30 nxt[++tot]=head[a]; 31 vet[tot]=b; 32 head[a]=tot; 33 } 34 35 int dfs(int u) 36 { 37 flag[u]=1; 38 int e=head[u]; 39 while(e) 40 { 41 int v=vet[e]; 42 if(!match[v]||!flag[match[v]]&&dfs(match[v])) 43 { 44 match[v]=u; 45 return 1; 46 } 47 e=nxt[e]; 48 } 49 return 0; 50 } 51 52 int calc(int mid) 53 { 54 int in=0; 55 int out=0; 56 int cir=0; 57 memset(head,0,sizeof(head)); 58 tot=0; 59 for(int i=1;i<=m;i++) 60 { 61 if(x[i]==mid&&y[i]==mid) 62 { 63 cir=1; 64 continue; 65 } 66 if(y[i]==mid){in++; continue;} 67 if(x[i]==mid){out++; continue;} 68 add(x[i],y[i]); 69 } 70 71 memset(match,0,sizeof(match)); 72 int maxmatch=0; 73 for(int i=1;i<=n;i++) 74 { 75 memset(flag,0,sizeof(flag)); 76 if(dfs(i)) maxmatch++; 77 } 78 int del=m-in-out-cir-maxmatch; //无用,删 79 int plus=n-1-maxmatch; //无关中心,加 80 int t=2*(n-1)-in-out+1-cir; //中心相关 81 return del+plus+t; 82 } 83 84 int main() 85 { 86 //freopen("cf387d.in","r",stdin); 87 //freopen("cf387d.out","w",stdout); 88 scanf("%d%d",&n,&m); 89 for(int i=1;i<=m;i++) scanf("%d%d",&x[i],&y[i]); 90 int ans=oo; 91 for(int i=1;i<=n;i++) ans=min(ans,calc(i)); 92 printf("%d\n",ans); 93 return 0; 94 } 95 96
null
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步