POJ 1637 Sightseeing tour 建图+网络流

本文探讨了如何判断一个包含单向边和双向边的混合图是否存在欧拉回路,详细介绍了通过调整边的方向和使用网络流算法进行判定的方法。

题意:

  给定一个混合图,所谓混合图就是图中既有单向边也有双向边,现在求这样的图是否存在欧拉回路。

分析:

  存在欧拉回路的有向图,必须满足[入度==出度],现在,有些边已经被定向,所以我们直接记录度数即可,对于无向边呢?

  对于这样的边,我们只需要先随便定向,然后记录出入度。(这些边只用来计算出入度,不用于网络流建图)

  然后我们开始建图。现在极有可能有些点是不满足[入度==出度]的,所以我们要通过一些变向操作,使得图中所有点满足判定。

  如果一个点入度和出度的奇偶性不同,那整张图一定是不合法的。因为改变一条边的方向对端点的入度和出度是同时影响的,且是反向的,比如入度加一出度减一,或者出度加一入度减一,因此无论如何,那样的点都不可能满足判定条件的;

  随后,我们对于:

  所有入度>出度的点,从超级源点连一条容量为(入度-出度)/2的边;

  所有出度>入度的点,向超级汇点连一条容量为(出度-入度)/2的边;

  这样,一单位流量的需求,意味着有这么多边需要变向来使图满足判定条件。所以那些边可以变向,我们就使它的贡献为1 。

  所以,对于我们曾随便定向的那些无向边,我们在网络流建图中,向它们相反方向建一条流量为1的边(与我们随便定的向相反)。

  之后检验整张图与源点汇点连得边是否满流,满流则possible,不满则impossible。

代码:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<queue>
 7 #define ms(a,x) memset(a,x,sizeof(a))
 8 using namespace std;
 9 const int inf=0x3f3f3f3f;
10 const int N=1005;
11 struct edge{int x,y,d;}w[N];
12 struct node{int y,z,nxt;}e[N*2];
13 int in[N],ot[N],S,T,q[N],h[N],c=1;
14 int n,m,sm=0,tot=0,d[N],k,cas,flg;
15 void add(int x,int y,int z){
16     e[++c]=(node){y,z,h[x]};h[x]=c;
17     e[++c]=(node){x,0,h[y]};h[y]=c;
18 } bool bfs(){
19     int f=1,t=0;ms(d,-1);
20     q[++t]=S;d[S]=0;
21     while(f<=t){
22         int x=q[f++];
23         for(int i=h[x],y;i;i=e[i].nxt)
24         if(d[y=e[i].y]==-1&&e[i].z)
25         d[y]=d[x]+1,q[++t]=y;
26     } return (d[T]!=-1);
27 } int dfs(int x,int f){
28     if(x==T) return f;int w,tmp=0;
29     for(int i=h[x],y;i;i=e[i].nxt)
30     if(d[y=e[i].y]==d[x]+1&&e[i].z){
31         w=dfs(y,min(e[i].z,f-tmp));
32         if(!w) d[y]=-1;
33         e[i].z-=w;e[i^1].z+=w;
34         tmp+=w;if(tmp==f) return f;
35     } return tmp;
36 } void dinic(){
37     while(bfs()) tot+=dfs(S,inf);
38 } int main(){
39     scanf("%d",&cas);while(cas--){
40         scanf("%d%d",&n,&m);flg=0;
41         ms(in,0);ms(ot,0);ms(h,0);
42         c=1;S=0,T=n+1;sm=0,tot=0;
43         for(int i=1;i<=m;i++)
44         scanf("%d%d%d",&w[i].x,&w[i].y,&w[i].d),
45         in[w[i].y]++,ot[w[i].x]++;
46         for(int i=1;i<=n;i++){
47             if((in[i]&1)^(ot[i]&1))
48             {flg=1;break;}
49             if(in[i]>ot[i]) //sm+=in[i]-ot[i],
50             add(S,i,(in[i]-ot[i])/2);
51             if(in[i]<ot[i]) sm+=ot[i]-in[i],
52             add(i,T,(ot[i]-in[i])/2); 
53         } if(flg){puts("impossible");continue;}
54         for(int i=1;i<=m;i++)
55         if(!w[i].d) add(w[i].y,w[i].x,1);
56         dinic();sm>>=1;
57         if(tot==sm) puts("possible");
58         else puts("impossible");
59     } return 0;
60 }
最大流

 

  

转载于:https://www.cnblogs.com/Alan-Luo/p/10242344.html

先展示下效果 https://pan.quark.cn/s/a4b39357ea24 遗传算法 - 简书 遗传算法的理论是根据达尔文进化论而设计出来的算法: 人类是朝着好的方向(最优解)进化,进化过程中,会自动选择优良基因,淘汰劣等基因。 遗传算法(英语:genetic algorithm (GA) )是计算数学中用于解决最佳化的搜索算法,是进化算法的一种。 进化算法最初是借鉴了进化生物学中的一些现象而发展起来的,这些现象包括遗传、突变、自然选择、杂交等。 搜索算法的共同特征为: 首先组成一组候选解 依据某些适应性条件测算这些候选解的适应度 根据适应度保留某些候选解,放弃其他候选解 对保留的候选解进行某些操作,生成新的候选解 遗传算法流程 遗传算法的一般步骤 my_fitness函数 评估每条染色体所对应个体的适应度 升序排列适应度评估值,选出 前 parent_number 个 个体作为 待选 parent 种群(适应度函数的值越小越好) 从 待选 parent 种群 中随机选择 2 个个体作为父方和母方。 抽取父母双方的染色体,进行交叉,产生 2 个子代。 (交叉概率) 对子代(parent + 生成的 child)的染色体进行变异。 (变异概率) 重复3,4,5步骤,直到新种群(parentnumber + childnumber)的产生。 循环以上步骤直至找到满意的解。 名词解释 交叉概率:两个个体进行交配的概率。 例如,交配概率为0.8,则80%的“夫妻”会生育后代。 变异概率:所有的基因中发生变异的占总体的比例。 GA函数 适应度函数 适应度函数由解决的问题决定。 举一个平方和的例子。 简单的平方和问题 求函数的最小值,其中每个变量的取值区间都是 [-1, ...
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值