Problem - 387D - Codeforces

乔治喜欢图表。最重要的是,他喜欢有趣的图。我们将假设一个有向图是有趣的,如果它符合以下标准。
该图不包含任何多弧。
 有一个顶点v(我们称她为中心),这样对于图形u的任何顶点,图形都包含弧(u,v)和(v,u)。请注意,该图还包含循环(v,v)。
 除中心点外,所有顶点的outegree等于2,除中心点外,所有顶点的indegree等于2。顶点u的outegree是指从u出去的弧数,顶点u的indegree是指从u进去的弧数。
 然而,并不是所有事情都那么简单。乔治得到了一个有n个顶点和m条弧的有向图作为礼物。该图没有任何多弧。由于乔治喜欢有趣的图形,他想稍微改变一下所赠送的图形,把它变成一个有趣的图形。在一次改动中,他可以从图中删除一个任意的现有弧,或者在图中增加一个任意的弧。
乔治想知道:为了从他得到的图形中获得一个有趣的图形,他需要的最少改动次数是多少?请帮助乔治,找出问题的答案。
输入
 第一行包含两个隔开空间的整数n和m(2≤n≤500,1≤m≤1000)--呈现的图形中顶点和弧的数量。
接下来的每一行都包含两个空间分隔的整数ai, bi (1 ≤ ai, bi ≤ n) --图的弧的描述。对(ai,bi)意味着该图包含一个从顶点号ai到顶点号bi的弧。可以保证所呈现的图形不包含多条弧。
假设图中的顶点编号为1到n。
输出
 打印一个整数 - 乔治问题的答案。
例子
 inputCopy
 3 7
 1 1
 2 2
 3 1
 1 3
 3 2
 2 3
 3 3
 输出拷贝
 0
 输入复制
 3 6
 1 1
 2 2
 3 1
 3 2
 2 3
 3 3
 输出拷贝
 1
 输入复制
 3 1
 2 2
 输出拷贝
 6
 备注
 关于有向图的更多信息,请访问:http://en.wikipedia.org/wiki/Directed_graph
在第一个例子中,该图已经很有趣了,它的中心是顶点3。
题解:
我们看到n有500,直接枚举每个点为中心点,分开计算,由于去掉中心点后,我们就成了剩下n - 1个点直间出度与入度都变为1,我们首先默认构造n - 1个点需要依次连接,首尾连接,所以是n - 1次,然后看其中一个点是否需其他点有连接,删除
然后找最大匹配,每找到一个,cnt -= 2,相当于有一个出度与入度是不需要增加和删除的
#include<iostream>
#include<algorithm>
#include<string>
#include<queue>
#include<vector>
#include<map>
#include<cstring>
#include<cmath>
#include<set>
using namespace std;
#define int long long
typedef pair<int,int> PII;
int n,m;
int a[505][505];
int vis[505];
int link[505];
int ans = 1e9;
int ask(int x)
{
	int cnt = 0;
	for(int i  = 1;i <= n;i++)
	{
		if(!a[i][x])
		{
			cnt ++;
		}
		if(i == x)
		continue;
		if(!a[x][i])
		cnt++;
	}
	return cnt;
}
int dfs(int x,int y)
{
	for(int i = 1;i <= n;i++)
	{
		if(vis[i]||!a[x][i]||i == y)
		{
			continue;
		}
		vis[i] = 1;
		if(!link[i]||dfs(link[i],y))
		{
			link[i] = x;
			return 1;
		}
	}
	return 0;
}
int check(int x)
{
	memset(link,0,sizeof link);
	int cnt = 0;
	for(int i = 1;i <= n;i++)
	{
		if(i == x)
		continue;
		memset(vis,0,sizeof vis);
		dfs(i,x);
		cnt ++;
		for(int j = 1;j <= n;j++)
		{
			if(j == x)
			continue;
			if(a[i][j])
			cnt++;
		}
	}
	for(int i = 1;i <= n;i++)
	{
		if(i == x)
		continue;
		if(link[i])
		cnt -= 2;
	}
	return cnt;
}
void solve()
{
	cin >> n >> m;
	for(int i = 1;i <= m;i++)
	{
		int x,y;
		cin >> x >> y;
		a[x][y] = 1;
	} 
	for(int i = 1;i <= n;i++)
	{
		ans = min(ans,ask(i) + check(i));
	}
	cout << ans;
}
//1 2 3 4 5
//
signed main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);
//	cout.tie(0);
	int t = 1;
//	cin >> t;
    while(t--)
	{
		solve();
	} 
}
//5
//2 4 6 8 10 7 9 5 3 1
//1 3 5 7 9 6 8 4 2
//2 4 1 3


















