HDU 5348 MZL's endless loop 给边定向(欧拉回路,最大流)
题意:
给一个所有你可能想得到的奇葩无向图,要求给每条边定向,使得每个点的入度与出度之差不超过1。输出1表示定向往右,输出0表示定向往左。
思路:
网络流也是可以解决的!!应该挺简单理解的。但是由于复杂度的问题,EK和Dinic都搞不定,ISAP才行。
利用欧拉回路的思想。既然每个点的入度与出度之差不超过1,那么在每两个奇数度的点添加1条无向边并不会影响到什么。那么先添加一些边进去,使得所有点的度都是偶数的。先随意帮每条边定个方向,进行建新图(用于跑最大流),假设u->v,那么u的出度就是可以给v的(当且仅当这条边反转时),建边u->v,容量为1。添加超级源点s连接到所有【出度大于入度的点】,容量为(出度-入度)/2,表示它有这么多个出度可以赠人。将所有【入度大于出度的点】连一条边到超级汇点t,容量为(入度-出度)/2,表示需要这么多的入度。接着跑一遍最大流(结果必定是满流的,即所有点的出度=入度),每条有流的边就需要将原来随意定下的方向反过来。参考
#include <bits/stdc++.h>
#define INF 0x7f7f7f7f
#define pii pair<int,int>
#define LL long long
using namespace std;
const int N=;
struct node
{
int from, to, cap, flow, has;
node(){};
node(int from, int to,int cap,int flow,int has):from(from),to(to),cap(cap),flow(flow),has(has){};
}edge[N*];
int chu[N], ru[N], vis1[N], ans[N*], edge_cnt;
vector<int> vect[N], rev[N], md; //图的反向边在这,反向BFS时用的。
vector<pii> g; void init(int up)
{
md.clear();
g.clear();
memset(chu,,sizeof(chu));
memset(ru, ,sizeof(ru));
edge_cnt=;
for(int i=; i<=up; i++) vect[i].clear(),rev[i].clear();
} void add_node(int from,int to,int cap,int flow,int has)
{
edge[edge_cnt]=node(from, to, cap, flow, has);
rev[to].push_back(edge_cnt); //反向,用于ISAP的BFS
vect[from].push_back(edge_cnt++);
} void change() //修改原来定下方向的边
{
for(int i=; i<edge_cnt; i++)
{
node e=edge[i];
if( e.has>= && e.flow> ) ans[e.has]= -ans[e.has];
}
} bool isok(int n) //判断是否已经满足要求
{
for(int j=; j<=n; j++) if( abs(chu[j]-ru[j])> ) return false;
return true;
} int num[N], p[N], d[N], cur[N], vis[N]; //最大流用的
deque<int> que;
void BFS(int s,int e) //模板
{
memset(vis, , sizeof(vis));
que.clear();
que.push_back(e);
vis[e]=;
d[e]=;
num[]=; //gap可以在这更新 while(!que.empty())
{
int x=que.front();que.pop_front();
for(int i=; i<rev[x].size(); i++)
{
node e=edge[rev[x][i]];
if(!vis[e.from])
{
vis[e.from]=;
d[e.from]=d[e.to]+;
++num[d[e.from]];
que.push_back(e.from);
}
}
}
} int Augment(int s,int e) //模板
{
int ed=e, big=INF;
while(ed!=s)
{
node &e=edge[p[ed]];
big=min(big, e.cap-e.flow);
ed=edge[p[ed]].from;
}
ed=e;
while(ed!=s)
{
edge[p[ed]].flow+=big;
edge[p[ed]^].flow-=big;
ed=edge[p[ed]].from;
}
return big; //找到的流
} int max_flow(int n, int s, int e) //最大流模板
{
int ans_flow=;
memset(num, , sizeof(num));
BFS(s, e); //更新d数组
int x=s;
memset(cur, ,sizeof(cur));
while(d[s]<n)
{
if(x==e)
{
ans_flow+=Augment(s,e);
x=s;
}
int ok=;
for(int i=cur[x]; i<vect[x].size(); i++)
{
node &e=edge[vect[x][i]];
if(e.cap>e.flow && d[x]==d[e.to]+)
{
ok=;
p[e.to]=vect[x][i]; //记录边号
cur[x]=i;
x=e.to;
break;
}
}
if(!ok)
{
int m=n-;
for(int i=; i<vect[x].size(); i++)
{
node e=edge[vect[x][i]];
if(e.cap>e.flow) m=min(m, d[e.to]);
}
if(--num[d[x]]==) break;
d[x]=m+;
num[d[x]]++;
cur[x]=;
if(x!=s) x=edge[p[x]].from;
}
}
return ans_flow;
} int cal(int n, int s, int e)
{
if(isok(n)) return ; //已经满足要求了,不用跑最大流
int mcnt=g.size(), ncnt=;; //奇数度的点需要补边
md.clear();
for(int i=; i<=n; i++) if((chu[i]+ru[i])&) md.push_back(i);
for(int i=; i<md.size(); i+=)
{
g.push_back(make_pair(md[i],md[i+]));
chu[md[i]]++, ru[md[i+]]++;
} //建图***************
memset(vis1,,sizeof(vis1));
for(int i=; i<g.size(); i++)
{
int a=g[i].first;
int b=g[i].second;
int h= i<mcnt? i: -; if(!vis1[a]) ncnt++; //统计新图中的点数
if(!vis1[b]) ncnt++; add_node(a, b, , , h); //这是给定的边
add_node(b, a, , , -); if(!vis1[a]&&chu[a]>ru[a]) //添加源点
{
vis1[a]=;
int cnt=(chu[a]-ru[a])/;
add_node(, a, cnt, , -);
add_node(a, , , , -); }
if(!vis1[b]&&ru[b]>chu[b]) //添加汇点
{
vis1[b]=;
int cnt=(ru[b]-chu[b])/;
add_node(b, n+, cnt, , -);
add_node(n+, b, , , -);
}
} //最大流************
max_flow(ncnt+, s, e); //ncnt+2是表示点数 //修改一下答案******
change();
} int main()
{
freopen("input.txt", "r", stdin);
int t, n, m, a, b;
cin>>t;
while(t--)
{
scanf("%d%d",&n,&m);
init(n+);
for(int i=; i<m; i++)
{
scanf("%d %d", &a, &b);
chu[a]++, ru[b]++;
ans[i]=;
g.push_back(make_pair(a,b));
}
cal(n, , n+);
for(int i=; i<m; i++) printf("%d\n",ans[i]);
}
return ;
}
AC代码
附送个数据产生程序(跑完最大流后再测试一下是否满足要求了):
#include <bits/stdc++.h>
#define INF 0x7f7f7f7f
#define pii pair<int,int>
#define LL long long
using namespace std;
const int N=; int main()
{
freopen("output.txt", "w+", stdout);
int t=;//例子数
int a, b;
puts("");
srand(time());
while(t--)
{
a=((int)rand())%+;//点数
b=((int)rand())%min((a*a),)+;//边数
printf("\n\n%d %d\n\n", a, b); for(int i=; i<b; i++)
{
int u=((int)rand())%a+;
int v=((int)rand())%a+;
printf("%d %d\n",u,v);
}
}
return ;
}
数据产生器
HDU 5348 MZL's endless loop 给边定向(欧拉回路,最大流)的更多相关文章
- Hdu 5348 MZL's endless loop (dfs)
题目链接: Hdu 5348 MZL's endless loop 题目描述: 给出一个无向图(有环,有重边),包含n个顶点,m条边,问能否给m条边指定方向,使每个顶点都满足abs(出度-入度)< ...
- 2015 Multi-University Training Contest 5 hdu 5348 MZL's endless loop
MZL's endless loop Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Oth ...
- HDU 5348 MZL's endless loop(DFS去奇数度点+欧拉回路)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5348 题目大意:给你一张图,有n个点,和m条无向边,让你把m条无向边变成有向边,使得每个节点的|出度- ...
- HDU 5348 MZL's endless loop
乱搞题...第一直觉是混合图的欧拉通路,但是感觉并没有多大关系.最终AC的做法是不断的寻找欧拉通路,然后给边标号.所有边访问了一遍,所有点访问了一遍,效率是o(n+m).不存在-1的情况. #incl ...
- 图论 HDOJ 5348 MZL's endless loop
题目传送门 /* 题意:给一个n个点,m条边的无向图,要求给m条边定方向,使得每个定点的出入度之差的绝对值小于等于1. 输出任意一种结果 图论:一个图,必定存在偶数个奇度顶点.那么从一个奇度定点深搜, ...
- 2015多校.MZL's endless loop(欧拉回路的机智应用 || 构造)
MZL's endless loop Time Limit: 3000/1500 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Oth ...
- hdu5348 MZL's endless loop(欧拉回路)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud MZL's endless loop Time Limit: 3000/1500 ...
- hdu 5348 MZL's endless loop
给一个无向图(事实上是有向的.可是没有指定边的方向),你须要指定边的方向,使得每一个点入度和出度相差不超过1. 事实上就是找很多条路径.合起来能走完这个图..先统计各个顶点的度.度为奇数必是起点或终点 ...
- [2015hdu多校联赛补题]hdu5348 MZL's endless loop
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5348 题意:给你一个无向图,要你将无向图的边变成有向边,使得得到的图,出度和入度差的绝对值小于等于1, ...
随机推荐
- 用ScriptEngine在java中和javascript交互的例子(JDK6新特性)
package demo7; import java.util.Arrays; import java.util.List; import javax.script.Invocable; import ...
- POJ 1001 Exponentiation(JAVA,BigDecimal->String)
题目 计算实数a的n次方,具体输出格式看案例 import java.util.*; import java.math.*; public class Main { public static voi ...
- POJ 1759
Garland Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 1236 Accepted: 547 Descriptio ...
- 2015年4月 非常干货之Python资源大全
[非常干货之Python资源大全]Python是一门美妙的语言,简单易用,容易提升.它是一门主流语言,却没有其它专业语言的弊病,从游戏,ML,GUI到科学和数学有着巨量的函数库. 直击现场 <H ...
- Android OpenGL 学习笔记 --开始篇
转自: http://www.cnblogs.com/TerryBlog/archive/2010/07/09/1774475.html 1.什么是 OpenGL? OpenGL 是个专业的3D程序接 ...
- Linux command: usermod -- 改变用户状态
应用举例: 1. usermod -g newuser newuser force use GROUP as new primary group. 一般时候是默认的,也是必须的(不能更改).2. 指定 ...
- jQuery 实验教程
jQuery 实验教程 jQuery 简介.语法及事件处理 jQuery 以其特有的简练的代码风格,极大得改变了 JavaScript 代码编写的方式.本教程以实例代码为基础,讲解 jQuery 的使 ...
- iOS CoreAnimation剖析
零.前言 这里没有太多的代码细节,只是探索iOS动画的基本概念,以及其抽象模型,数学基础等.我们学习一个知识的时候一般有两个部分,抽象部分和形象部分,抽象好比语言的语法,是规则,形象好比具体的句子,可 ...
- 291. Word Pattern II
题目: Given a pattern and a string str, find if str follows the same pattern. Here follow means a full ...
- 机器人学 —— 机器人视觉(Bundle Adjustment)
今天完成了机器人视觉的所有课程以及作业,确实是受益匪浅啊! 最后一个话题是Bundle Adjustment. 机器人视觉学中,最顶尖的方法. 1.基于非线性优化的相机位姿估计 之前已经在拟合一篇中, ...