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