在题目中在慢慢细说概念
1.HDU - 3018 Ant Trip
题目大意:又N个村庄,M条道路。问须要走几次才干将全部的路遍历

解题思路:这题问的是有关欧拉路的判定
欧拉路就是每条边仅仅能走一次,且要遍历全部的边,简单的说就是一笔画(图连通)
这道题是无向图的欧拉路。无向图的欧拉路的判定:全部点的度数都是偶数度,或者仅仅有两个点的度是奇数度,且图要是连通图

知道欧拉路是什么后,这题就比較好做了,第一件事就是找到有几个连通块,然后再推断一下每一个连通块须要几笔才干完毕就好了

#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
using namespace std;
#define N 100010int node[N];
int n, m;
int p[N];
int vis[N], vis2[N];
int num[N];
map<int,int> M;int find(int x) {return x == p[x] ? x : p[x] = find(p[x]);
}void init() {M.clear();memset(node, 0, sizeof(node));memset(vis, 0, sizeof(vis));memset(num, 0, sizeof(num));memset(vis2, 0, sizeof(vis2));int x, y, px, py;for (int i = 0; i <= n; i++)p[i] = i;for (int i = 0; i < m; i++) {scanf("%d%d", &x, &y);px = find(x);py = find(y);if (px != py) {p[px] = py;}node[x]++;node[y]++;vis[x] = 1;vis[y] = 1;}
}void solve() {int cnt = 0;for (int i = 0; i <= n; i++) {if (vis[i]) {int x = find(i);if(!vis2[x]) {vis2[x] = 1;M[x] = cnt++;}}}for (int i = 0; i <= n; i++) {if (vis[i] && node[i] % 2) {int x = find(i);num[M[x]]++;}}int ans = cnt;for(int i = 0; i < cnt; i++) if(num[i])ans += ((num[i] - 1) / 2);printf("%d\n", ans);
}int main() {while (scanf("%d%d", &n, &m) != EOF) {init();solve();}return 0;
}

2.POJ - 1386 Play on Words

题目大意:问全部的单词是否能首尾相连

解题思路:这题也是求欧拉路的,仅仅只是这题是有向的
有向图的欧拉路判定:首先,要是连通的。接着就分成两种了,一种是全部点的入度等于出度,还有一种是仅仅有两个点的入度不等于出度。且当中一个点的入度比出度大一,还有一个点的出度比入度大一

#include <cstdio>
#include <cstring>
#include <cstdlib>
#define N 30
#define M 1010int in[N], out[N], n;
char str[M];
int p[N], vis[N];
int find(int x) {return x == p[x] ? x : p[x] = find(p[x]);
}void init() {scanf("%d", &n);for (int i = 0; i < N; i++)vis[i] = out[i] = in[i] = 0;for (int i = 0; i < N; i++)p[i] = i;int len, x, y, px, py;for (int i = 0; i < n; i++) {scanf("%s", str);len = strlen(str);x = str[0] - 'a';y = str[len - 1] - 'a'; in[x]++;out[y]++;vis[x] = 1;vis[y] = 1;px = find(x);py = find(y);if(px != py) {p[px] = py;}}
}bool connect() {int start = 0;for (; !vis[start]; start++);for (int i = start + 1; i < N; i++) {if (vis[i] && find(i) != find(start)) {return false;}}return true;
}void solve() {int cnt = 0; bool mark = false;bool flag1 = false, flag2 = false;for (int i = 0; i < N; i++) {if (in[i] - out[i] != 0) {cnt++;if (cnt >= 3)break;if (abs(in[i] - out[i]) != 1) {mark = true;break;}if (in[i] - out[i] == -1)flag1 = true;if (in[i] - out[i] == 1)flag2 = true;}}if(mark || cnt >= 3) {printf("The door cannot be opened.\n");return ;}bool flag3 = connect();if (cnt == 0 && flag3) {printf("Ordering is possible.\n");}else if (cnt == 2 && flag1 && flag2 && flag3) {printf("Ordering is possible.\n");}else {printf("The door cannot be opened.\n");}}int main() {int test;scanf("%d", &test);while (test--) {init();solve();}return 0;
}

下面的题目都要用到Fluery算法
3.POJ - 1041 John’s trip

题目大意:有n个城市,m条路,问是否能走遍全部的路,最后又回到起点

解题思路:问是否能形成欧拉回路,并要求输出路径的题目
首先是欧拉回路的判定,对无向图来说,全部的点的度数都为偶数就是欧拉回路了。对有向图来说。是全部的点的入度等于出度

事实上上面的判定我少加了一个条件,那就是图连通
这题是无向图的。所以判定起来比較简单,关键是怎样输出路径了
事实上这题是非常坑的,所要求的输出最小字典序,事实上并不须要,仅仅须要常规的输出就能够了
事实上这一题也不须要了解fluery算法,仅仅须要dfs输出就能够了。dfs能够保证路线连通,在设置一个标记就能够输出全部路径了

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <stack>
#include <vector>
using namespace std;
#define N 2000
#define M 50struct Edgs{int junc, street;Edgs(int s = 0, int j = 0) : junc(j), street(s) {}
};int degrees[M];
vector<Edgs> E[N];
stack<int> stk;
bool vis[N];
int Max, x, y, z;void Euler(int u) {for (int i = 0; i < E[u].size(); i++) {if (!vis[E[u][i].street]) {vis[E[u][i].street] = true;Euler(E[u][i].junc);stk.push(E[u][i].street);}}
}void solve() {for (int i = 0; i < M; i++) {if (degrees[i] & 1) {printf("Round trip does not exist.\n");return ;}}Euler(Max);while (!stk.empty()) {printf("%d ", stk.top());stk.pop();}printf("\n");
}void init() {scanf("%d", &z);Max = max(x, y);memset(degrees, 0, sizeof(degrees));memset(vis, 0, sizeof(vis));for(int i = 0; i < N; i++)E[i].clear();E[x].push_back(Edgs(z,y));E[y].push_back(Edgs(z,x));degrees[x]++;degrees[y]++;while(scanf("%d%d", &x, &y) && x + y) {scanf("%d", &z);E[x].push_back(Edgs(z,y));E[y].push_back(Edgs(z,x));degrees[x]++;degrees[y]++;}
}int main() {while (scanf("%d%d", &x, &y) != EOF && x + y) {init();solve();}return 0;
}

4.POJ - 2230 Watchcow

题目大意:有N个点,M条边,要求每条边都走两次。且最后回到原点,输出走的点

解题思路:每条边走两次,不就相当于把一条边变成两条边吗,那就变成两条边再去遍历就能够了

#include <cstdio>
#include <cstring>
#include <vector>
using namespace std;
#define N 10010vector<int> Edgs[N];
int n, m;
int vis[N];void init() {for (int i = 1; i <= n; i++)Edgs[i].clear();int x, y;for (int i = 0; i < m; i++) {scanf("%d%d", &x, &y);Edgs[x].push_back(y);Edgs[y].push_back(x);}
}void Euler(int u) {int tmp;for (int i = 0; i < Edgs[u].size(); i++) {tmp = Edgs[u][i];if(!tmp)continue;Edgs[u][i] = 0;Euler(tmp);}printf("%d\n", u);
}int main() {while (scanf("%d%d", &n, &m) != EOF ) {init();Euler(1);}return 0;
}

5.POJ - 2404 Jogging Trails

插播一题欧拉回路+floyd+状态压缩的题目

题目大意:有N个点,M条路。每条路都有对应的权值。如今有一个人想把全部的路都跑遍,最后又回到原点。问最小权值是多少

解题思路:跑欧拉回路的话,肯定能使权值到达最小。
所以问题就变成了,通过增边将M条路构造成欧拉回路
问题进一步变成了怎样增边才干使权值达到最低,这就须要用到状态压缩dp了

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
#define N 20
#define INF 0x3f3f3f3f
#define S (1<<15)int n, m, ans;
int dis[N][N], degrees[N], dp[S];void floyd() {for (int k = 0; k < n; k++)for (int i = 0; i < n; i++)for (int j = 0; j < n; j++)if(dis[i][k] != INF && dis[k][j] != INF && dis[i][j] > dis[i][k] + dis[k][j])dis[i][j] = dis[i][k] + dis[k][j];
}int dfs(int state) {if (state == 0) { return 0;}if (dp[state] != -1) {return dp[state];}dp[state] = INF;for (int i = 0; i < n; i++) {if (state & (1 << i)) {for (int j = 0; j < n; j++) {if ((state & (1 << j)) && i != j) {dp[state] = min(dp[state], dfs(state ^ (1 << i) ^ (1 << j)) + dis[i][j]);} }}}return dp[state];
}void solve() {int state = 0;for (int i = 0; i < n; i++) {if (degrees[i] % 2) {state |= (1 << i);}}memset(dp, -1,sizeof(dp));ans += dfs(state);printf("%d\n", ans);
}void init() {ans = 0;memset(dis, 0x3f, sizeof(dis));for (int i = 0; i < N; i++) degrees[i] = 0;for (int i = 0; i < n; i++)dis[i][i] = 0;int x, y, z;scanf("%d", &m);for (int i = 0; i < m; i++) {scanf("%d%d%d",&x, &y, &z);dis[x - 1][y - 1] = dis[y - 1][x - 1] = min(dis[x - 1][y - 1], z);ans += z;degrees[x - 1]++;degrees[y - 1]++;}floyd();
}int main() {while (scanf("%d", &n) != EOF && n) {init();solve();}return 0;
}

6.POJ - 2337 Catenyms

题目大意:这题就比較有难度了。问是否能将字符串头尾相连,假设能够的话,输出字典序最小的字符串

解题思路:參考了学长的。有向欧拉路的推断就不说了,关键是怎样输出字典需最小的
首先。先给全部的字符串排序
依照fleury算法。输出时根据栈里的内容输出,而栈是从顶究竟输出的。也就是说。压栈的时候。先将字典序大的压栈就可以

#include <cstdio>
#include <cstring>
#include <stack>
#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;
#define N 30
#define M 1010vector<int> v[N];
int vis[M], p[N], in[N], out[N];
char word[M][N];
int n;
stack<int> stk;int find(int x) {return x == p[x] ? x : p[x] = find(p[x]);
}
void output() {while (!stk.empty()) {printf("%s", word[stk.top()]);stk.pop();if (!stk.empty()) {printf(".");}}
}int cmp (const void *a, const void *b) {return strcmp((char *)a, (char *)b);
}void push (int u, int v) {for (int i = n - 1; i >= 0; i--) {if(!vis[i] && word[i][0] - 'a' == u && word[i][strlen(word[i]) - 1] - 'a' == v)  {stk.push(i);vis[i] = 1;return ;}}
}
void dfs(int u) {while (!v[u].empty()) {int tmp = *(v[u].begin());v[u].erase(v[u].begin());dfs(tmp);push(u, tmp);}
}void solve() {int root;for (int i = 0; i < N; i++) {if (vis[i]) {root = find(i);break;}}for (int i = 0; i < N; i++) {if (vis[i] && find(i) != root) {printf("***");return ;}}int start = 0, cnt;for (int i = 0; i < N; i++) {if (abs(in[i] - out[i]) > 1) {printf("***");return ;}if (abs(in[i] - out[i]) == 1) {cnt++;if(in[i] - out[i] == 1)start = i;}}if(cnt > 2) {printf("***");return ;}if(!cnt)start = word[0][0] - 'a';memset(vis, 0, sizeof(vis));dfs(start);output();
}void init() {scanf("%d", &n);for (int i = 0; i < n; i++)scanf("%s", word[i]);qsort(word, n, sizeof(word[0]), cmp);memset(vis, 0, sizeof(vis));for (int i = 0; i < N; i++) {v[i].clear();in[i] = out[i] = 0;p[i] = i;}int x, y;for (int i = 0; i < n; i++) {x = word[i][0] - 'a';y = word[i][strlen(word[i]) - 1] - 'a';v[x].push_back(y);vis[x] = vis[y] = 1;in[x]++;out[y]++;p[find(x)] = find(y);}
}int main() {int test;scanf("%d", &test);while(test--) {init();solve();printf("\n");}return 0;
}

接下来的题目,算是欧拉路的应用吧

7.UVA - 10040 Ouroboros Snake

题目大意:有个轮子上面有2 * n个数字,有n个数字是0,n个数字是1。这个轮子非常奇妙,在纸上滚动时。会将轮子上面的0。1印在纸张上。细致看纸张上面的数字,从头開始。分别从第1个到第2^n个截取出长度为n的二进制数,会发现这些二进制数包括了0—-(1 << n)-1的全部数
如今要求你按规则输出第k个开头,长度为n的二进制数

解题思路:由于包括了全部0–(1 << n)-1的数。这些长度为n的二进制数都是0-1构成的,且全部的出度等于入度,所以这就形成了一个欧拉回路了
因此在构造这个轮子在纸张上打印的字时能够依照输出欧拉回路的方法构造。

具体的能够看这篇文章。里面有对代码的具体讲解代码具体解释

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 16
#define S (1<<16)
int pow2[N];
bool vis[S][2];
int ans[S];
int cnt, n, k;
void erule(int s) {for (int i = 0; i < 2; i++) {if (!vis[s][i]) {vis[s][i] = true;erule(((s << 1) + i) % pow2[n - 1]);ans[cnt++] = i;}}
}int main() {pow2[0] = 1;for (int i = 1; i < N; i++)pow2[i] = pow2[i - 1] * 2;while (scanf("%d%d", &n, &k) != EOF && n + k) {memset(vis, 0, sizeof(vis));memset(ans, 0, sizeof(ans));cnt = 0;erule(0);cnt += n - 2 - k;int t = 0;for (int i = 0; i < n; i++)t = t * 2 + ans[cnt--];printf("%d\n", t);}return 0;
}

8.HDU - 2894 DeBruijin
这题跟上一题相似

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 16
#define S (1<<16)
int pow2[N];
bool vis[S][2];
int ans[S];
int cnt, n, k;
void erule(int s) {for (int i = 0; i < 2; i++) {if (!vis[s][i]) {vis[s][i] = true;erule(((s << 1) + i) % pow2[n - 1]);ans[cnt++] = i;}}
}int main() {pow2[0] = 1;for (int i = 1; i < N; i++)pow2[i] = pow2[i - 1] * 2;while (scanf("%d", &n) != EOF && n) {memset(vis, 0, sizeof(vis));memset(ans, 0, sizeof(ans));cnt = 0;erule(0);printf("%d ", pow2[n]);cnt += n - 2;for (int i = pow2[n]; i > 0; i--)printf("%d",ans[cnt--]);printf("\n");}return 0;
}

9.POJ - 1780 Code

这题的话。我就当个搬运工。附上大神的具体讲解
具体讲解

#include <cstdio>
#include <cstring>
using namespace std;
#define N 1000010char ans[N];
bool vis[N];
int pow10[8];
int n;void solve() {if(n == 1) {printf("0123456789\n");return ;}memset(vis, 0, sizeof(vis));for (int i = 0; i < n; i++)ans[i] = '0';int cur = n, now = 0, i = 0;vis[0] = true;while (cur < pow10[n] + n - 1) {now %= pow10[n - 1];for (; i < 10; i++) {if (!vis[now * 10 + i]) {vis[now * 10 + i] = true;now = now * 10 + i;ans[cur++] = i + '0';i = 0;break;}}if (i == 10 && cur < pow10[n] + n - 1) {cur--;now = (ans[cur - n + 1] - '0') * pow10[n - 1] + now;vis[now] = false;i = now  % 10 + 1;now /= 10;}}ans[cur] = '\0';printf("%s\n", ans);
}void init() {pow10[0] = 1;for (int i = 1; i < 8; i++)pow10[i] = pow10[i - 1] * 10;
}int main(){init();while (scanf("%d", &n) != EOF && n) {solve();}return 0;
}

转载于:https://www.cnblogs.com/blfbuaa/p/6999527.html

图论--欧拉路,欧拉回路(小结)相关推荐

  1. 图论-欧拉路(UVA10054)(HDU1116)

    首先说一下定义: 欧拉路:从图中某点出发可以遍历全图,图中的每条边通过且只能通过一次. 欧拉回路:具有欧拉路性质且起点位置与终点位置相同. 主要问题就是一个图中是否存在欧拉路,和打印欧拉路路径. 先说 ...

  2. 模板 - 欧拉路、欧拉回路(一笔画问题)

    整理的算法模板合集: ACM模板 目录 非递归版 普通递归版 HierholzersHierholzersHierholzers算法(输出字典序最小的答案) FleuryFleuryFleury算法 ...

  3. 欧拉回路与欧拉路(模板)

    欧拉回路 欧拉图: 就是从任意一个点开始都可以一笔画完整个图 半欧拉图: 必须从某个点开始才能一笔画完整个图. 对于无向图 , 是欧拉图当且仅当 是连通的且没有奇度顶点. 对于无向图 , 是半欧拉图当 ...

  4. hrbust 哈理工oj 1633 word!word!【欧拉路、欧拉回路的有向图判断】

      word!word! Time Limit: 1000 MS Memory Limit: 32768 K Total Submit: 58(20 users) Total Accepted: 25 ...

  5. 欧拉路和欧拉回路知识

    概念 如果图G中的一个路径包括每个边恰好一次,则该路径称为欧拉路径(Euler path). 如果一个回路是欧拉路径,则称为欧拉回路(Euler circuit). [1] 具有欧拉回路的图称为欧拉图 ...

  6. 图论总结(欧拉路+Floyd所有结点最短+Bellman-Ford算法+SPFA+Dijsktra算法+Tarjan算法+最小生成树(prim+kruskal) )

    目录 欧拉路 判断欧拉路是否存在: ​​​​​​​ 最短路: Floyd算法 : ​​​​​​​​​​​​​​ Bellman-Ford: ​​​​​​​ Dijkstra 单源最短路 先附上例题: ...

  7. 海亮Day2:差分约束、拓扑排序、欧拉路

    海亮第二天,想着说预习一下的,可是昨天10h+都没有把那六道题打完,就打了四道,上午就讲完课了,还是延续昨天的博客,今天接着总结.. 欧拉路 开头就是特别经典的七桥问题,讲欧拉路一定会讲到的问题,也就 ...

  8. 数据结构实验之图论八:欧拉回路

    Description 在哥尼斯堡的一个公园里,有七座桥将普雷格尔河中两个岛及岛与河岸连接起来. 能否走过这样的七座桥,并且每桥只走一次?瑞士数学家欧拉最终解决了这个问题并由此创立了拓扑学.欧拉通过对 ...

  9. #1182 : 欧拉路·三(有向图的欧拉路)

    #1182 : 欧拉路·三 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 小Hi和小Ho破解了一道又一道难题,终于来到了最后一关.只要打开眼前的宝箱就可以通关这个游戏了 ...

最新文章

  1. Numpy 从数值范围创建数组
  2. oracle排序后的第一条记录
  3. 人工智能-基于U^2-Net的肖像画生成算法
  4. MVC中使用 事物
  5. jdk中自带 jstat,jconsole,jps,jmap,jhat使用
  6. hadoop的序列化与java的序列化区别
  7. WordPress WP cleanfix插件‘eval()’函数跨站请求伪造漏洞
  8. 【整理】Server.Variables属性大全
  9. Meta-Learning
  10. Django admin组件源码流程
  11. linux面板带csf防火墙,linux csf 防火墙 防止少量的ddos cc攻击很有效
  12. 分布式光纤管道泄漏监测系统管道泄漏检测技术分析
  13. 【文本分类】采用同义词的改进TF-IDF权重的文本分类
  14. 软考分类精讲-软件管理
  15. 世界杯的狂欢也是黑灰产的狂欢?
  16. HTML CSS JS 网页设计作业「我的家乡吉林」
  17. 集成融云的视频通话功能
  18. spring--ApplicationContextAware
  19. ggplot2——图例篇
  20. 量化交易主要是什么?

热门文章

  1. dot3_bump_mapping
  2. 应用构建工具包 Ecere SDK
  3. 致广大关注《网络规划设计师考试案例梳理、真题透解与强化训练》读者朋友的一封信...
  4. 微软发布全新多核心操作系统原型:Barrelfish
  5. gpupdate /force 遇报错解决过程
  6. 如何使用日志进行程序调试_如何使用日志节省调试时间
  7. (C++)A+B 输入输出练习VI 每行的第一个数N,表示本行后面有N个数。
  8. java培训分享:学习java开发的优势是什么
  9. 为什么匿名内部类参数必须为final类型
  10. 分析PHP中单双引号的误区和双引号小隐患