George and Interesting Graph
George loves graphs. Most of all, he loves interesting graphs. We will assume that a directed graph is interesting, if it meets the following criteria:
- The graph doesn't contain any multiple arcs;
- There is vertex v (we'll call her the center), such that for any vertex of graph u, the graph contains arcs (u, v) and (v, u). Please note that the graph also contains loop (v, v).
- The outdegree of all vertexes except for the center equals two and the indegree of all vertexes except for the center equals two. The outdegree of vertex u is the number of arcs that go out of u, the indegree of vertex u is the number of arcs that go in u. Please note that the graph can contain loops.
However, not everything's that simple. George got a directed graph of n vertices and m arcs as a present. The graph didn't have any multiple arcs. As George loves interesting graphs, he wants to slightly alter the presented graph and transform it into an interesting one. In one alteration he can either remove an arbitrary existing arc from the graph or add an arbitrary arc to the graph.
George wonders: what is the minimum number of changes that he needs to obtain an interesting graph from the graph he's got as a present? Help George and find the answer to the question.
Input
The first line contains two space-separated integers n and m (2 ≤ n ≤ 500, 1 ≤ m ≤ 1000) — the number of vertices and arcs in the presented graph.
Each of the next m lines contains two space-separated integers ai, bi (1 ≤ ai, bi ≤ n) — the descriptions of the graph's arcs. Pair (ai, bi) means that the graph contains an arc from vertex number ai to vertex number bi. It is guaranteed that the presented graph doesn't contain multiple arcs.
Assume that the grah vertices are numbered 1 through n.
Output
Print a single integer — the answer to George's question.
Examples
Input
3 7 1 1 2 2 3 1 1 3 3 2 2 3 3 3
Output
0
Input
3 6 1 1 2 2 3 1 3 2 2 3 3 3
Output
1
Input
3 1 2 2
Output
6
一、原题地址
二、大致题意
给出一个有向图,n个顶点m条边。
可以确定一个中心顶点。
1、除了这个中心顶点之外其他的点都要满足存在两个出度和两个入度。
2、中心顶点 u 需要对任意顶点 v(包括自己)有一条(u,v)的边和(v,u)的边,即他们都要互通。
现在可以删除和添加边,使得给出的原图满足以上情况。询问删除和添加的最小操作次数。
三、思路
枚举每个点可能成为中心的情况。
对于每个情况的我们假设中心点为 C 。则我们先去掉那些和 C 有关系的边,同时要记录这些入C和出C的边的数量,记为 in 和out 。那么在去掉中心 C 之后,原图剩下来的那些点应该需要满足入度和出度都等于1。这就相当于将一个点拆为一个入度点和一个出度点,那么我们跑一次二分图匹配,得到的值记录为maxx。
那么在二分图中真正在跑的边数量应该是 m-(in+out)我们记为workedge
实际上我们在当前情况下的二分匹配中真正需要删除的边的数量应该是workedge-maxx。相当于将那些度数大于1的废边删除。将这个数值记为del。
我们需要添加在匹配图里的边,应该是那些度数不足1的点的个数,就是点数减去匹配数,那些没匹配上的都是需要加边的,即(n-1)-maxx。
中心点与各顶点之间原本没有的边我们也需要加上,即(2 * (n - 1) - (out + in))。这里还需要讨论原来中心点有没有自环。
四、代码
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#include<queue>
#include<functional>
using namespace std;
const int inf = 0x3f3f3f3f;
int n, m;
vector<int>t[505], vec[505];
bool visit[505];
int match[505];
int find(int u)
{
for (int i = 0; i < vec[u].size(); i++) //vec储存匹配关系
{
int v = vec[u][i];
if (!visit[v])
{
visit[v] = 1;
if (match[v] == -1 || find(match[v]))
{
match[v] = u;
return true;
}
}
}
return false;
}
int Match()
{
int ans = 0;
memset(match, -1, sizeof(match));
for (int i = 1; i <= n; i++)
{
memset(visit, 0, sizeof(visit));
if (find(i))
ans++;
}
return ans;
}
void read()
{
scanf("%d %d", &n, &m);
for (int i = 1; i <= m; i++)
{
int u, v;
scanf("%d %d", &u, &v);
t[u].push_back(v);
}
}
int work(int nx)
{
int in = 0, out = 0;
bool tag = false;
for (int i = 1; i <= n; i++)
{
vec[i].clear();
if (i == nx)
{
out += t[i].size();
int ss = t[i].size();
for (int k = 0; k < ss; k++)
{
if (t[i][k] == i)
{
tag = true; break;
}
}
continue;
}
int siz = t[i].size();
for (int j = 0; j < siz; j++)
{
int to = t[i][j];
if (to == nx)
{
in++;
continue;
}
vec[i].push_back(to);
}
}
//将原图的边转换到二分匹配图上
int workedge = m - (in + out);//在匹配图中剩下的边数
if (tag)out--;
int maxx=Match(); //最大匹配数
int del = workedge - maxx; //二分匹配中真正需要删除的边
int add = n - 1 - maxx; //需要添加在匹配图里的边
int ret = add+del + (2 * (n - 1) - (out + in));//中心点与各顶点之间原本没有的边我们也需要加上
if (!tag)ret++;
return ret;
}
int main()
{
read();
int ans = inf;
for (int i = 1; i <= n; i++)
{
ans = min(ans, work(i));
}
printf("%d\n", ans);
getchar();
getchar();
}