Codeforces 387D George and Interesting Graph【思维+二分匹配】

本文探讨了一种特定类型的有向图——有趣图,并提供了解决方案,以通过添加或删除最少数量的边,使给定图变成有趣图。文章详细介绍了算法步骤,包括选择中心节点、确保节点间的连接性及调整节点的出入度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

D. George and Interesting Graph
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

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
Note

For more information about directed graphs, please visit: http://en.wikipedia.org/wiki/Directed_graph

In the first sample the graph already is interesting, its center is vertex 3.



题目大意:


给出N个点,M条边的有向图,现在我们可以任意添加一条边,也可以任意删除一条边,使得最终,有n-1个点的出度==入度并且出度为2.另外一个点设定为Center,并且要求这个点和其他各个点,都有两条边(u,v)和(v,u),并且不约束出度入度最终是多少。



思路:


①我们O(n)枚举这样一个中心点,然后暴力去判定这个Center和其他各个点都要相连的边是否缺少,如果缺少了的,都需要补上。


②然后我们此时如果搞定了Center点的约束之后,我们考虑剩下n-1个点,我们知道,最终要使得这n-1个点的出入度都是2,然而这里已经用掉了一个出度连入center点,也用掉了一个入度,使得center连入,那么我们剩下的任务就是将这n-1个点的出入度都控制在1即可。


③那么对于剩下的边,我们建图跑出最大二分匹配数,那么对于一个匹配来讲,我们将其保留,对于一条匹配边(u,v)来讲,我们就解决了点u的出度和点v的入度,那么如果我们能够将这n个点都匹配上,那么其实就相当于解决了所有点的问题,也就是说,此时所有点的出度和入度我们都控制在了1。

那么对于当前情况,我们跑出最大二分匹配数之后(maxn),如果其不足n-1个,那么补上(n-1-maxn),别忘了,还要删除原来存在的多余的边。


④过程维护一下,注意细节即可,时间复杂度O(n^2*m);


Ac代码:

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int match[600];
int vis[600];
int a[600][600];
int x[4545];
int y[4545];
int n,m;
int find(int u)
{
    for(int i=1;i<=n;i++)
    {
        if(a[u][i]==1&&vis[i]==0)
        {
            vis[i]=1;
            if(match[i]==-1||find(match[i]))
            {
                match[i]=u;
                return 1;
            }
        }
    }
    return 0;
}
int Slove(int u)
{
    int ans=0,tot=0;
    memset(a,0,sizeof(a));
    for(int i=1;i<=m;i++)a[x[i]][y[i]]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            if(a[i][j]==1&&(i!=u)&&(j!=u))tot++;
            if(a[i][j]==0&&(i==u||j==u))
            {
                ans++;
            }
            if(i==u||j==u)a[i][j]=0;
        }

    }
    memset(match,-1,sizeof(match));
    int output=0;
    for(int i=1;i<=n;i++)
    {
        memset(vis,0,sizeof(vis));
        if(i==u)continue;
        if(find(i))output++;
    }
    ans+=n-1-output;
    ans+=tot-output;
    return ans;
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d",&x[i],&y[i]);
        }
        int ans=0x3f3f3f3f;
        for(int i=1;i<=n;i++)
        {
            int tmp=Slove(i);
            ans=min(ans,tmp);
        }
        printf("%d\n",ans);
    }
}








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值