题意
给定一个有向图,每次操作可以随意添加或删除任一条边。求让该无向图满足:
1. 1. 1. 存在一个中心点 v v v(自由指定),从该点到其他任一一点 u u u 都存在边 ( v , u ) ( u , v ) (v,u)\ (u,v) (v,u) (u,v),并且该点存在自环。
2. 2. 2. 除中心点外的所有点,出度和入度均为 2 2 2。
所需要的最少操作次数。
在确定了中心点之后,去掉该中心点及所有与该点有关的边,剩下的所有点的出度和入度均为 1,则此时剩下的图是由若干个环组成。
鉴于此时所有点入边和出边的唯一性,考虑将所有点拆分为入点和出点,所有入点在左集合,所有出点在右集合。将所有的边载入该二分图后,最大匹配数即为可以保留的边,其余需要删除。对于未被匹配到的 孤 寡 点 数 目 / 2 孤寡点数目/2 孤寡点数目/2 ,即为需要加入的边数。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int INF = 0x3fffffff;
const int N=550;
int g[N][N];
int gg[N][N];
int vis[N],match[N];
int n,m;
int find(int u){
for(int i=1;i<=n;i++){
if(!vis[i]&&gg[u][i]){
vis[i]=true;
if(match[i]==-1||find(match[i])){
match[i]=u;
return 1;
}
}
}
return 0;
}
signed main(){
cin>>n>>m;
for(int i=0;i<m;i++){
int u,v;
cin>>u>>v;
g[u][v]=1;
}
int ret=INF;
for(int i=1;i<=n;i++){
int use=0;
int ans=0;
for(int j=1;j<=n;j++){
if(i==j){//自环
if(!g[i][j])
ans++;
else
use++;
}
else{
if(!g[i][j])
ans++;
else
use++;
if(!g[j][i])
ans++;
else
use++;
}
}
memset(match,-1,sizeof(match));
memcpy(gg,g,sizeof(gg));
for(int j = 0;j<=n;j++)
gg[i][j]=gg[j][i]=0;
int x=0;
for(int k=1;k<=n;k++){
memset(vis,0,sizeof(vis));
if(find(k))
x++;
}
use+=x;
int left=n-1-x;
ret=min(ret,m-use+ans+left);
}
cout<<ret<<endl;
}