大体题意:
给你一个无向图,要求不能增边的,给边定向,使得图中入度等于出度的点尽可能多,输出结果,和边的方向!
思路:
赛后补得,请教了学长的思路(想了一天= =),感觉思路很巧妙:
首先,无向图中奇度点的个数一定是偶数个(我才知道,感觉很神奇= = ~)
那么我们可以把每个奇度的点与一个新的虚拟结点相连,这样最后我们会得到一个全都是偶数度数的无向图,那么必然存在一条欧拉回路,我们只需要求出所有的欧拉回路,这就是结果!结果在把于虚拟节点相连的边删去即可!
想一想就是这么回事,欧拉回路 经过每个边一次,这样就保证了入度等于出度,那么答案也就是偶数度数的个数!
关于存边有两个方法:
用邻接表或者 set存。
邻接表 直接判断边是否访问过即可!
对于set 更直接,直接删除访问过的点即可!
注意:
1.用邻接表注意数组大小要适当,因为虚拟节点的存在,实际中的边 比你想像的要多不少 错了N遍了~~
2.在一个就是dfs时要dfs所有的点!这里也错了好几遍,因为这个图可能不是全连通的,那么就需要dfs所有的点!
详细见代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 40000 + 1;
const int inf = 0x3f3f3f3f;
struct Node{
int v, next;
}p[maxn<<1];
int e,d[300],head[300];
bool vis[maxn<<1];
vector<pair<int,int> >path;
void addedge(int u,int v){
p[e].v = v;
p[e].next = head[u];
head[u] = e++;
}
void dfs(int k){
for (int i = head[k]; i != -1; i = p[i].next){
if (vis[i])continue;
vis[i] = vis[i^1] = 1;
int v = p[i].v;
path.push_back(make_pair(k,v));
// printf("^^^ %d %d\n",k,v);
dfs(v);
}
}
int main(){
int T;
scanf("%d",&T);
while(T--){
memset(head,-1,sizeof head);
memset(d,0,sizeof d);
memset(vis,0,sizeof vis);
path.clear();
e = 0;
int n, m, s = 1;
scanf("%d %d",&n, &m);
for (int i = 0; i < m; ++i){
int u,v;
scanf("%d %d",&u, &v);
addedge(u,v);
addedge(v,u);
s = u;
d[u]++,d[v]++;
}
int ans = 0;
for (int i = 1; i <= n; ++i){
if (d[i] & 1){
++ans;
// printf("%d\n",i);
addedge(i,233);
addedge(233,i);
}
}
for (int i = 1; i <= n; ++i){
dfs(i);
}
int len = path.size();
printf("%d\n",n - ans);
for (int i = 0; i < len; ++i){
if (path[i].first == 233 || path[i].second == 233)continue;
printf("%d %d\n",path[i].first,path[i].second);
}
}
return 0;
}
/**
1
7 2
3 7
4 2
**/