[CodeForce375]E图论

题目描述

There are n cities and m two-way roads in Berland, each road connects two cities. It is known that there is no more than one road connecting each pair of cities, and there is no road which connects the city with itself. It is possible that there is no way to get from one city to some other city using only these roads.

The road minister decided to make a reform in Berland and to orient all roads in the country, i.e. to make each road one-way. The minister wants to maximize the number of cities, for which the number of roads that begins in the city equals to the number of roads that ends in it.

算法思路

比赛的时候手速太慢,结果没有及时交上去,囧。。。。
题目很简单,将一个无向图转化成一个有向图,并且尽量让入度等于出度的节点尽量多。并且要求输出一个解。
首先我们考虑两种极端的情况,如果在一个联通分量中,所有的点度数都是偶数,那么我们很快就可以知道这是一个欧拉图,所有的点经过一种转化都可以成为入度等于出度的点。如果一个联通分量中所有的点度数都是奇数,那么则没有一个点经过转化之后入度可以等于出度。
那么我们考虑一个图当中的点有些的度数是偶数,有些的度数是奇数的情况。我们可以得到下面的结论:
1. 奇数度的结点数目为偶数,由握手定理可得。
2. 从一个奇数度的结点构造一条路径,其终点也一定是奇数度的结点
所以我们立刻可以想到,在一条路径中,离开一个结点的次数一定等于进入这个结点的次数。所以使用DFS,解决。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;

#define MAXN 205

vector<int>ans;
int grid[MAXN][MAXN];
int deg[MAXN];
int n,m,t,o;

void Dfs(int cur)
{
    //cout << cur << endl;
    int i;

    for(i=1;i<=n;i++){
        if(grid[cur][i]){
            grid[cur][i] = grid[i][cur] = 0;
            deg[cur]--;
            deg[i]--;
            ans.push_back(cur);
            ans.push_back(i);
            Dfs(i);
            break;
        }
    }
    return;
}

int main()
{
    //freopen("input","r",stdin);
    int i,tmp1,tmp2;
    scanf("%d",&t);

    while(t--){
        memset(grid,0,sizeof(grid));
        memset(deg,0,sizeof(deg));
        ans.clear();
        o = 0;

        scanf("%d%d",&n,&m);

        for(i=0;i<m;i++){
            scanf("%d%d",&tmp1,&tmp2);
            grid[tmp1][tmp2] = 1;
            grid[tmp2][tmp1] = 1;
            deg[tmp1]++;
            deg[tmp2]++;
        }

        for(i=1;i<=n;i++)
            if(deg[i]&1)o++;
        for(i=1;i<=n;i++)
            if(deg[i]&1)Dfs(i);
        for(i=1;i<=n;i++)
            if(deg[i])Dfs(i);

        printf("%d\n",n-o);
        for(i=0;i<ans.size();i+=2){
            printf("%d %d\n",ans[i],ans[i+1]);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值