codeforces 723F : st-Spanning Tree

时间:2023-12-10 21:14:02

Description

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.

Input

The first line contains a positive integer t (1 ≤ t ≤ 200) — the number of testsets in the input.

Each of the testsets is given in the following way. The first line contains two integers n and m (1 ≤ n ≤ 200, 0 ≤ m ≤ n·(n - 1) / 2) — the number of cities and the number of roads in Berland.

The next m lines contain the description of roads in Berland. Each line contains two integers u and v (1 ≤ u, v ≤ n) — the cities the corresponding road connects. It's guaranteed that there are no self-loops and multiple roads. It is possible that there is no way along roads between a pair of cities.

It is guaranteed that the total number of cities in all testset of input data doesn't exceed 200.

Pay attention that for hacks, you can only use tests consisting of one testset, so t should be equal to one.

Output

For each testset print the maximum number of such cities that the number of roads that begins in the city, is equal to the number of roads that ends in it.

In the next m lines print oriented roads. First print the number of the city where the road begins and then the number of the city where the road ends. If there are several answers, print any of them. It is allowed to print roads in each test in arbitrary order. Each road should be printed exactly once.

Example
Input
2
5 5
2 1
4 5
2 3
1 3
3 5
7 2
3 7
4 2
Output
3
1 3
3 5
5 4
3 2
2 1
3
2 4
3 7

正解:构造+贪心

解题报告:

  这道题比赛的时候%王队的代码,结果王队写萎了一个地方,我不仅写萎了同一个地方,还自己弄出了一个新错误,直接FST。考虑我们希望使得s和t的度数尽可能小。那么显然,我们需要把不含s和t的边能连上的就连上,那么我们可以得到S、T和若干连通块。并且这些连通块之间没有边。我们考虑我们优先选择S、T和连通块相连,能连则连。

  其次我们考虑如果直接连接S和T,事实上是不划算的,因为如果把S和T分别和一个未被连入整体的连通块的话,同样减少一点度数,可以得到更优秀的答案(多连入了一个连通块)。所以我们接着考虑连接某个连通块,他与S、T都相连。需要注意:找到一个这样的连通块之后,我们只需要之后的对于这种连通块我们都只需要连上S或者T就可以了,显然选择度数比较多的那个会更优。最后我们再考虑S、T直接相连的情况。

  有很多细节,注意一下。

 //It is made by jump~
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
using namespace std;
typedef long long LL;
const int inf = (<<);
const int MAXN = ;
const int MAXM = ;
int n,m,ecnt,s,t,ds,dt,root;
int ans[MAXM],cnt,father[MAXN];
bool use[MAXM];
int ok[MAXM][],jilu[MAXN][];
struct edge{
int x,y;
}e[MAXM];
inline int find(int x){ if(father[x]!=x) father[x]=find(father[x]); return father[x]; }
inline void rr(){ printf("No"); exit(); }
inline int getint()
{
int w=,q=; char c=getchar();
while((c<'' || c>'') && c!='-') c=getchar(); if(c=='-') q=,c=getchar();
while (c>='' && c<='') w=w*+c-'', c=getchar(); return q ? -w : w;
} inline void work(){
n=getint(); m=getint(); for(int i=;i<=m;i++) e[i].x=getint(),e[i].y=getint();
s=getint(); t=getint(); ds=getint(); dt=getint(); int r1,r2; for(int i=;i<=n;i++) father[i]=i;
for(int i=;i<=m;i++) {
if(e[i].x==s || e[i].y==s) continue; if(e[i].x==t || e[i].y==t) continue;
r1=find(e[i].x); r2=find(e[i].y);
if(r1!=r2) { father[r1]=r2; ans[++cnt]=i; use[i]=; }
}
bool flag=false;
for(int i=;i<=m;i++) {
if(use[i]) continue; if((e[i].x==s && e[i].y==t) || (e[i].x==t && e[i].y==s) ) { flag=true; root=i; continue; }
if(e[i].x==s) ok[find(e[i].y)][]=,jilu[find(e[i].y)][]=i;
if(e[i].y==s) ok[find(e[i].x)][]=,jilu[find(e[i].x)][]=i;
if(e[i].x==t) ok[find(e[i].y)][]=,jilu[find(e[i].y)][]=i;
if(e[i].y==t) ok[find(e[i].x)][]=,jilu[find(e[i].x)][]=i;
}
for(int i=;i<=n;i++) {
if(find(i)!=i) continue; if(i==s || i==t) continue;
if(ok[i][]+ok[i][]==) rr();
else if(ok[i][]+ok[i][]==) {
if(ok[i][]) ds--,ans[++cnt]=jilu[i][],use[jilu[i][]]=,r1=find(s),r2=find(i),father[r2]=r1;
else if(ok[i][]) dt--,ans[++cnt]=jilu[i][],use[jilu[i][]]=,r1=find(t),r2=find(i),father[r2]=r1;
}
}
if(ds< || dt<) rr();
for(int i=;i<=n;i++) {
if(find(i)!=i) continue; if(ok[i][]+ok[i][]<=) continue;
ds--; dt--; r1=find(s); r2=find(i); father[r2]=r1; r1=find(i); r2=find(t); father[r1]=r2;
ans[++cnt]=jilu[i][]; ans[++cnt]=jilu[i][];
use[jilu[i][]]=use[jilu[i][]]=;
break;
}
if(ds< || dt<) rr();
for(int i=;i<=n;i++) {
if(find(i)!=i) continue; if(ok[i][]+ok[i][]<=) continue;
if(find(i)==find(s)) continue;
if(ds>dt) ds--,ans[++cnt]=jilu[i][];
else dt--,ans[++cnt]=jilu[i][];
}
if(ds< || dt<) rr();
if(find(s)!=find(t)) {
if(flag) { ds--,dt--,ans[++cnt]=root; }
else rr();
}
if(ds< || dt<) rr();
printf("Yes\n");
for(int i=;i<=cnt;i++) printf("%d %d\n",e[ans[i]].x,e[ans[i]].y);
} int main()
{
work();
return ;
}