题意:
判断混合图中是否存在欧拉回路,如果存在欧拉回路,输出路径。
思路:
欧拉回路 存在每条边经过且只经过一次后回到原点的路径
在混合图中存在欧拉回路,需要满足以下条件:
1.把所有无向边任意规定一个方向后,对于每个点,满足 |入度-出度| % 2 == 0
2.按照上面已经规定的方向,利用 无向边 建图(有向边忽略掉),然后对于每个结点u,如果in[u]<out[u], 建边(s, u, |入度-出度| / 2);如果in[u]>out[u], 建边(u, t, |入度-出度| / 2)
括号中的内容分别是 (起点,终点,容量)
3.新建的图G'中找最大流,如果满流就说明欧拉回路是存在的~
欧拉回路的输出我感觉挺难想的。。我太弱了吧.....T_T
就是把所有用到的边都存下来~(原图中的有向边必然要存下来),但是对于原图中的无向边,我们要根据刚才最大流时每条边中的流量关系来确定其方向:如果规定方向后,跑出最大流时这条无向边中有流量,说明要将这条边反向~
然后利用某个算法(见代码)~~来把欧拉回路找粗来。。。
code:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
#include<queue>
#include<map>
#include<set>
#include<cmath>
#include<cstdlib>
using namespace std;
#define INF 0x3f3f3f3f
#define PI acos(-1.0)
#define mem(a, b) memset(a, b, sizeof(a))
typedef pair<int,int> pii;
typedef long long LL;
//------------------------------
const int maxn = 205;
int n,m;
struct Edge{
int to, cap, rev;//终点 容量 反向边
Edge(int to_ = 0, int cap_ = 0, int rev_ = 0){
to = to_;
cap = cap_;
rev = rev_;
}
};
vector<Edge> g[maxn], qg[maxn];//qg[maxn]是欧拉回路用到的边
int level[maxn];//顶点到源点的距离标号
int iter[maxn];
void add(int from, int to){//欧拉回路用到的边
Edge tmp1(to, 0, qg[to].size());
qg[from].push_back(tmp1);
}
void add_Edge(int from, int to, int cap){
Edge tmp1(to, cap, g[to].size());
g[from].push_back(tmp1);
Edge tmp2(from, 0, g[from].size()-1);
g[to].push_back(tmp2);
}
void bfs(int s){
memset(level, -1, sizeof(level));
queue<int> q;
level[s] = 0;
q.push(s);
while(!q.empty()){
int v = q.front();
q.pop();
for(int i = 0; i < g[v].size(); i++){
Edge& e = g[v][i];
if(e.cap > 0 && level[e.to] < 0){
level[e.to] = level[v] + 1;
q.push(e.to);
}
}
}
}
int dfs(int v, int t, int f){
if(v == t) return f;
for(int& i = iter[v]; i < g[v].size(); i++){
Edge& e = g[v][i];
if(e.cap > 0 && level[v] < level[e.to]){
int d = dfs(e.to, t, min(e.cap, f));
if(d > 0){
e.cap -= d;
g[e.to][e.rev].cap += d;
return d;
}
}
}
return 0;
}
int max_flow(int s, int t){
int flow = 0;
for(;;){
bfs(s);
if(level[t] < 0) return flow;
memset(iter, 0, sizeof(iter));
int f;
while((f = dfs(s, t, INF)) > 0){
flow += f;
}
}
}
//------------------上面是最大流模板部分 正确----------------------
int in[maxn], out[maxn];
int put[1000005];
int cnt = 0;
void print(int u){ //打印欧拉回路
for(int i = 0; i < qg[u].size(); i++){
Edge& et = qg[u][i];
if(!et.cap){
et.cap = 1;
print(et.to);
}
}
put[cnt++] = u;
}
void init(){
memset(G, 0, sizeof(G));
memset(in, 0, sizeof(in));
memset(out, 0, sizeof(out));
for(int i = 0; i < maxn; i++) g[i].clear();
for(int i = 0; i < maxn; i++) qg[i].clear();
n = Scan(); m = Scan();
int u, v;
char s[10];
for(int i = 1; i <= m; i++){
u = Scan();
v = Scan();
scanf("%s", s);
if(s[0] == 'U'){
add_Edge(u, v, 1);
}
else {
add(u, v);
}
out[u] ++;
in[v] ++;
}
}
void solve(){
for(int i = 1; i <= n; i++){
if(abs(out[i] - in[i]) % 2){
printf("No euler circuit exist\n");
return;
}
}
int sumv = 0;
for(int i = 1; i <= n; i++){
if(in[i] < out[i]){
add_Edge(0 , i, (out[i] - in[i]) / 2);
sumv += (out[i] - in[i])/2;
}
else if(out[i] < in[i]){
add_Edge(i, n+1, (in[i] - out[i]) / 2);
}
}
int ans = max_flow(0, n+1);
if(ans != sumv){
printf("No euler circuit exist\n");
return;
}
for(int i = 1; i <= n; i++){
for(int j = 0; j < g[i].size(); j++){
Edge et = g[i][j];
int v = et.to;
if(v == 0 || v == n+1 || !et.cap) continue; //建立了双向边,所以cap!=0的边说明其反向边中有流量,所以其实应该增加这条边
add(i, v);
}
}
cnt = 0;
print(1);
for(int i = cnt - 1; ~i; --i) printf("%d%c", put[i], i ? ' ' : '\n');
}
int main(){
int t;
scanf("%d",&t);
while(t--){
init();
solve();
if(t != 0) printf("\n");
}
return 0;
}
反正我判断是不是欧拉回路的时候用的时间很少的,我干囧好简单...但是我刚开始的时候并不会输出路径撒....sigh..