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, ...
随机推荐
- 使用Varnish代替Squid做网站缓存加速器的详细解决方案----转载
[文章作者:张宴 本文版本:v1.2 最后修改:2008.01.02 转载请注明出处:http://blog.s135.com] 我曾经写过一篇文章──<初步试用Squid的替代产品──Varn ...
- POJ2451 Uyuw's Concert(半平面交)
题意就是给你很多个半平面,求半平面交出来的凸包的面积. 半平面交有O(n^2)的算法,就是每次用一个新的半平面去切已有的凸包,更新,这个写起来感觉也不是特别好写. 另外一个O(nlogn)的算法是将半 ...
- .bash_profile和.bashrc的区别(如何设置生效)
/etc/profile:此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行.并从/etc/profile.d目录的配置文件中搜集shell的设置. /etc/bashrc:为每一个 ...
- python_pycharm介绍1
1. 常用设置 修改编程风格 File-Setting中,Editor下Colors&Fonts修改即可调整风格. 修改字体大小 pycharm默认字体太小,需调整些,Settings--&g ...
- Android 广播机制(两种注册方法)与中断广播
两种注册类型的区别是: 1)第一种不是常驻型广播,也就是说广播跟随activity的生命周期.注意: 在activity结束前,移除广播接收器. 2)第二种是常驻型,也就是说当应用程序关闭后,如果有信 ...
- struts2与spring mvc 的比较
1.传值: struts2通过set get来传值,而spring mvc 可以直接在方法里传值(String username,Model model)model也可以换成map来传值但不建义 mo ...
- linux fork函数与vfork函数,exit,_exit区别
man vfork: NAME vfork - create a child process and block parent SYNOPSIS #include <sys/types.h> ...
- js 去空格函数与正则
如果项目没有用到jQuery等框架的话,js本身又没有这样的函数,我们不得不自己写这样的函数,下面是函数的具体实现: //供使用者调用 function trim(s){ return trimRig ...
- Volley HTTP库系列教程(1)简介及优点
Transmitting Network Data Using Volley Get started Dependencies and prerequisites Android 1.6 (API ...
- debian系统安装Thinkpad T410s的无线网卡驱动:centrino Advanced-N 6200 2x2 AGN
前几天搞到手一台小黑:T410s.自带系统是win7.由于想学习debian,所以就搞成了双系统,安装了一套debian 6.0. 可是让我困惑的是在debian下,无法使用T410s的网卡,因为默认 ...