CF723E One-Way Reform

分析

首先,乍一看本题可能没有思路,但是手推一下这几组样例:

  • 样例一

其中入度等于出度的点为 1,3,5

  • 样例二

其中入度等于出度的点为 1,5,6

由此,我们可以发现,所以的入度等于出度的点,其入度与出度之和为偶数,于是我们可以猜想:最大化的满足入度等于出度的点,那么其中满足条件的节点的出度与入度之和为偶数

证明:

显然,图中的满足入度等于出度的点,所有与其相连的出边会且仅会被遍历到一次,依次类推,与其相连的所有入边都只会被遍历到一次,那么如果出度等于入度,该点的总度数必然为 (2 imes k) 次, 那么我们如果要最大化入度等于出度的点的数量,那么就需要尽量的构造出出入度之和为偶数的点

Solution

由上面的分析,我们可以发现,如果想要最大化图中入度与出度和为偶数的点,我们可以增加一个超级点 (x) ,并让 (x) 点与其他本身入度与出度和为奇数的点两边,这样,图中的所有点的入度与出度和均为偶数

那么,如果我们把这个图看为一个无向图,显然,此时的整个图边存在一个欧拉回路(或者说一个有向图存在欧拉回路的充要条件为所有顶点的入度等于出度且该图是连通图),那么我们只要跑一遍欧拉回路即可解决问题,总共的满足条件的节点个数即为原图中本身的总度数是偶数的点的数量

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<vector>
#define ll long long
using namespace std;

const ll maxn=210;
ll t,n,m,ret,pos;
ll used[maxn][maxn],sum[maxn];

inline void dfs(ll x)//欧拉回路 dfs 板子
{
	for(int i=1;i<=pos;i++)
	{
		if(used[x][i])
		{
			used[x][i]=0;
			used[i][x]=0;
			
			if(i!=pos&&x!=pos)
			{
				printf("%lld %d
",x,i);
			}
			
			dfs(i);
		}
	}
}

int main(void)
{
	scanf("%lld",&t);
	
	while(t--)
	{
		ret=0,pos=0;
		memset(sum,0,sizeof(sum));
		memset(used,0,sizeof(used));
		
		scanf("%lld%lld",&n,&m);
		
		for(int i=1;i<=m;i++)
		{
			ll x,y;
			scanf("%lld%lld",&x,&y);
			used[x][y]=1;
			used[y][x]=1;
			sum[x]++;
			sum[y]++;
		}
		
		pos=n+1;
		
		for(int i=1;i<=n;i++)
		{
			if(sum[i]%2==1)
			{
				used[pos][i]=used[i][pos]=1;
			}
			else ret++;
		}
		
		printf("%lld
",ret);
		
		for(int i=1;i<=n;i++)
		{
			dfs(i);
		}
	}
	
	return 0;
}
原文地址:https://www.cnblogs.com/jd1412/p/13771380.html