题意:

  给一个所有你可能想得到的奇葩无向图,要求给每条边定向,使得每个点的入度与出度之差不超过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 给边定向(欧拉回路,最大流)的更多相关文章

  1. Hdu 5348 MZL's endless loop (dfs)

    题目链接: Hdu 5348 MZL's endless loop 题目描述: 给出一个无向图(有环,有重边),包含n个顶点,m条边,问能否给m条边指定方向,使每个顶点都满足abs(出度-入度)< ...

  2. 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 ...

  3. HDU 5348 MZL's endless loop(DFS去奇数度点+欧拉回路)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5348 题目大意:给你一张图,有n个点,和m条无向边,让你把m条无向边变成有向边,使得每个节点的|出度- ...

  4. HDU 5348 MZL's endless loop

    乱搞题...第一直觉是混合图的欧拉通路,但是感觉并没有多大关系.最终AC的做法是不断的寻找欧拉通路,然后给边标号.所有边访问了一遍,所有点访问了一遍,效率是o(n+m).不存在-1的情况. #incl ...

  5. 图论 HDOJ 5348 MZL's endless loop

    题目传送门 /* 题意:给一个n个点,m条边的无向图,要求给m条边定方向,使得每个定点的出入度之差的绝对值小于等于1. 输出任意一种结果 图论:一个图,必定存在偶数个奇度顶点.那么从一个奇度定点深搜, ...

  6. 2015多校.MZL's endless loop(欧拉回路的机智应用 || 构造)

    MZL's endless loop Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Oth ...

  7. hdu5348 MZL's endless loop(欧拉回路)

    转载请注明出处: http://www.cnblogs.com/fraud/          ——by fraud MZL's endless loop Time Limit: 3000/1500 ...

  8. hdu 5348 MZL&#39;s endless loop

    给一个无向图(事实上是有向的.可是没有指定边的方向),你须要指定边的方向,使得每一个点入度和出度相差不超过1. 事实上就是找很多条路径.合起来能走完这个图..先统计各个顶点的度.度为奇数必是起点或终点 ...

  9. [2015hdu多校联赛补题]hdu5348 MZL's endless loop

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5348 题意:给你一个无向图,要你将无向图的边变成有向边,使得得到的图,出度和入度差的绝对值小于等于1, ...

随机推荐

  1. 程序员必须知道的git托管平台

    http://www.open-open.com/lib/view/open1420704561390.html

  2. FastReport报表

    http://www.fastreportcn.com/product/FASTREPORT_dotNET.html

  3. poj 1733(带权并查集+离散化)

    题目链接:http://poj.org/problem?id=1733 思路:这题一看就想到要用并查集做了,不过一看数据这么大,感觉有点棘手,其实,我们仔细一想可以发现,我们需要记录的是出现过的节点到 ...

  4. iframe父子兄弟之间调用传值(contentWindow && parent)

    iframe的调用包括以下几个方面:(调用包含html dom,js全局变量,js方法) 主页面调用iframe: iframe页面调用主页面: 主页面的包含的iframe之间相互调用: 主要知识点 ...

  5. jmeter 302请求测试

    需求,测试url:  http://test.123.com/123.action,请求该url之后会进行302跳转,判断跳转的页面是不是http://www.haha.com. 这个其实本质还是普通 ...

  6. C#反射Assembly 详细说明

    1.对C#反射机制的理解2.概念理解后,必须找到方法去完成,给出管理的主要语法3.最终给出实用的例子,反射出来dll中的方法 反射是一个程序集发现及运行的过程,通过反射可以得到*.exe或*.dll等 ...

  7. Gradle Goodness: Rename Ant Task Names When Importing Ant Build File

    Migrating from Ant to Gradle is very easy with the importBuild method from AntBuilder. We only have ...

  8. GetWindowText和GetDlgItemText的区别

    二者使用方法相同,入口点不一样. 举例: CString str;  /* if (GetDlgItem(IDC_Number1)->GetWindowText(str),str==" ...

  9. ios开发 ad hoc

    iOS证书分2种,1种是开发证书,用来给你(开发人员)做真机测试的:1种是发布证书,发布证书又分发布到app store的(这里不提及)和发布测试的ad hoc证书. 那ad hoc证书和开发证书区别 ...

  10. PHP组合模式、策略模式

    一.问题 模拟不同课程有不同的收费方式,并且能灵活改变(新增或删减),如讲座可以固定收费也可改为按时收费,研讨会也是. 二.模式简介及关键点 1.在父类代码中使用条件语句是一种退倒,可以用多态来代替条 ...