爬格子呀9.17(图论)
Posted romalzhih
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了爬格子呀9.17(图论)相关的知识,希望对你有一定的参考价值。
刘汝佳的紫书差不多就告一段落吧,我觉得可以了,怎么说呢,这书也陪着自己走了一年多了吧,也目睹了从一个啥也不会的萌新到一个稍微会一点的萌新的转变。
差不多开始下本书吧,自己也大三了,时间真的有点紧啊woctm
最喜欢的图论作为自己对这本书的谢幕,也好,也好
uva10735(欧拉回路+网络流)
题意:给一个图,图中有部分是向边,部分是无向边,要求判断是否存在欧拉回路,若存在,输出路径
解法:
1 #include<bits/stdc++.h> 2 #define REP(i, a, b) for(int i = (a); i < (b); i++) 3 #define MEM(a,x) memset(a,x,sizeof(a)) 4 #define INF 0x3f3f3f3f 5 #define MAXN 10000+10 6 using namespace std; 7 8 struct Euler 9 { 10 struct Edge { 11 int to, nxt; 12 Edge() {} 13 Edge(int x, int y) :to(x), nxt(y) {} 14 }edges[MAXN]; 15 int head[MAXN], n, E; 16 void init(const int &n) { 17 this->n = n; E = 0; 18 for (int i = 0; i <= n; i++)head[i] = -1; 19 } 20 void AddEdge(int f, int t) { 21 edges[++E] = Edge(t, head[f]); 22 head[f] = E; 23 } 24 stack<int >S; 25 bool vis[MAXN];//use when dfs 26 void dfs(int x) {//get EulerCircle 27 Edge e; 28 for (int i = head[x]; i != -1; i = e.nxt) { 29 e = edges[i]; 30 if (vis[i])continue; 31 vis[i] = 1; 32 dfs(e.to); 33 S.push(x); 34 } 35 } 36 void getEulerCircle() { 37 while (!S.empty())S.pop(); 38 memset(vis, 0, sizeof(vis)); 39 dfs(1); 40 for (; !S.empty(); S.pop()) { 41 printf("%d ", S.top()); 42 } 43 puts("1"); 44 } 45 }gg; 46 47 struct Dinic 48 { 49 struct Edge { 50 int from, to, cap, flow; 51 Edge(int u, int v, int c, int f) : 52 from(u), to(v), cap(c), flow(f) {} 53 }; 54 int n, s, t; 55 vector<Edge>edges; 56 vector< int>G[MAXN]; //gragh 57 bool vis[MAXN]; //use when bfs 58 int d[MAXN], cur[MAXN];//dist,now edge,use in dfs 59 void AddEdge(int from, int to, int cap) { 60 edges.push_back(Edge(from, to, cap, 0)); 61 edges.push_back(Edge(to, from, 0, 0)); 62 int top = edges.size(); 63 G[from].push_back(top - 2); 64 G[to].push_back(top - 1); 65 } 66 void init(int n, int s, int t) { 67 this->n = n; 68 this->s = s; 69 this->t = t; 70 edges.clear(); 71 for (int i = 0; i <= n; i++)G[i].clear(); 72 } 73 74 bool BFS() { 75 memset(vis, 0, sizeof(vis)); 76 queue<int>Q; 77 Q.push(s); d[s] = 0; vis[s] = 1; 78 while (!Q.empty()) { 79 int x = Q.front(); Q.pop(); 80 for (int i = 0; i < G[x].size(); i++) { 81 Edge &e = edges[G[x][i]]; 82 if (vis[e.to] || e.cap <= e.flow)continue; 83 vis[e.to] = 1; 84 d[e.to] = d[x] + 1; 85 Q.push(e.to); 86 } 87 } 88 return vis[t]; 89 } 90 int DFS(const int& x, int a) { 91 if (x == t || a == 0) { return a; } 92 int flow = 0, f; 93 for (int& i = cur[x]; i < G[x].size(); i++) { 94 Edge& e = edges[G[x][i]]; 95 if (d[x] + 1 != d[e.to])continue; 96 if ((f = DFS(e.to, min(a, e.cap - e.flow))) <= 0)continue; 97 e.flow += f; 98 edges[G[x][i] ^ 1].flow -= f;//?? 99 flow += f; a -= f; 100 if (!a) break; 101 } 102 return flow; 103 } 104 int MaxFlow(int s, int t) { 105 int flow = 0; 106 for (; BFS();) { 107 memset(cur, 0, sizeof(cur)); 108 flow += DFS(s, INF); 109 } 110 return flow; 111 } 112 void buildEuler(int n) { 113 for (int i = 1; i <= n; i++) { 114 for (int j = 0; j < G[i].size(); j++) { 115 Edge &e = edges[G[i][j]]; 116 if (e.to == s || e.to == t) continue; 117 if (!e.cap)continue; 118 if (e.flow == e.cap)gg.AddEdge(e.to, e.from); 119 else gg.AddEdge(e.from, e.to); 120 } 121 } 122 } 123 }g; 124 125 int d[MAXN];//degree = out - in 126 bool work(int n) { 127 int flow = 0; 128 REP(i, 1, n + 1) { 129 if (d[i] & 1)return 0; 130 if (d[i] > 0) { 131 g.AddEdge(g.s, i, d[i] >> 1); 132 flow += d[i] >> 1; 133 } 134 else if (d[i] < 0) 135 g.AddEdge(i, g.t, -(d[i] >> 1)); 136 } 137 if (flow != g.MaxFlow(0, n + 1)) return 0; 138 return 1; 139 } 140 141 int main() { 142 int T, x, y, n, m; 143 scanf("%d", &T); 144 for (char ch; T--;) { 145 scanf("%d%d", &n, &m); 146 g.init(n, 0, n + 1); 147 gg.init(n); 148 MEM(d, 0); 149 REP(i, 0, m) { 150 scanf("%d %d %c", &x, &y, &ch); 151 if (ch == ‘D‘) gg.AddEdge(x, y); 152 else g.AddEdge(x, y, 1); 153 d[x]++; d[y]--;//Degree 154 } 155 if (!work(n))puts("No euler circuit exist"); 156 else { 157 g.buildEuler(n); 158 gg.getEulerCircle(); 159 } 160 if (T)puts(""); 161 } 162 return 0; 163 }
uva1001
题意:
给出一些球,球内的时间为零,球之间的速度为10每单位。给两个点,求最短时间。
解法:
处理出任意两点之间的距离 && 做题的时候要大胆点hhh
1 #include<bits/stdc++.h> 2 #define REP(i, a, b) for(int i = (a); i < (b); i++) 3 #define MEM(a,x) memset(a,x,sizeof(a)) 4 #define INF 0x3f3f3f3f 5 #define MAXN 100+10 6 using namespace std; 7 struct node { int x, y, z, r; }p[MAXN]; 8 double g[MAXN][MAXN]; 9 10 double dis(node a,node b) { 11 double ans = sqrt( 12 (a.x - b.x)*(a.x - b.x) 13 + (a.y - b.y)*(a.y - b.y) 14 + (a.z - b.z)*(a.z - b.z)) 15 - (a.r + b.r); 16 return ans < 0 ? 0 : ans; 17 } 18 19 int main() { 20 int n, cnt = 0; 21 while (cin >> n && n != -1) { 22 REP(i, 0, n) cin >> p[i].x >> p[i].y >> p[i].z >> p[i].r; 23 cin >> p[n].x >> p[n].y >> p[n].z; p[n].r = 0; 24 cin >> p[n + 1].x >> p[n + 1].y >> p[n + 1].z; p[n + 1].r = 0; 25 26 MEM(g, INF); 27 REP(i, 0, n + 2)g[i][i] = 0; 28 REP(i, 0, n + 2)REP(j, 0, n + 2) g[i][j] = dis(p[i], p[j]); 29 30 REP(k, 0, n + 2)REP(i, 0, n + 2)REP(j, 0, n + 2) 31 g[i][j] = min(g[i][j], g[i][k] + g[k][j]); 32 33 g[n][n + 1] *= 10; 34 printf("Cheese %d: Travel time = %.0f sec ", ++cnt, g[n][n + 1]); 35 } 36 return 0; 37 }
uva820
题意:有一个计算机网络,输入节点数n,输入网络流源点和汇点src,des,再输入双向边数m。给出m条边的负载,求最大流。
解法:
网络流模板题
你想,流量其实就是运输物品,我们要求的就是从源点到汇点最多能运输多少单位的物品,
当物品变成水流的时候,他可以均匀的分布在所有边上,每个边上可以有的物品数就是这个边的容量,所有可行边的路径和就是我们要求的所谓“路径权值和”
这道题Dinic中的init有问题,改了一下就好了
1 #include<bits/stdc++.h> 2 #define REP(i, a, b) for(int i = (a); i < (b); i++) 3 #define MEM(a,x) memset(a,x,sizeof(a)) 4 #define INF 0x3f3f3f3f 5 #define MAXN 1000+10 6 using namespace std; 7 struct Edge { 8 int from, to, cap, flow; 9 }; 10 struct Dinic { 11 int n, m, s, t; 12 vector<Edge>edges; 13 vector<int>G[MAXN]; 14 bool vis[MAXN]; 15 int d[MAXN]; 16 int cur[MAXN]; 17 void init() { 18 edges.clear(); 19 for (int i = 0; i < MAXN; i++) G[i].clear(); 20 memset(d, 0, sizeof d); 21 } 22 void AddEdge(int from, int to, int cap) { 23 edges.push_back({ from, to, cap, 0 }); 24 edges.push_back({ to, from, 0, 0 }); 25 m = edges.size(); 26 G[from].push_back(m - 2); 27 G[to].push_back(m - 1); 28 } 29 bool BFS() { 30 int x, i; 31 memset(vis, 0, sizeof(vis)); 32 queue<int>Q; 33 Q.push(s); 34 d[s] = 0; 35 vis[s] = 1; 36 while (!Q.empty()) { 37 x = Q.front(), Q.pop(); 38 for (i = 0; i < G[x].size(); i++) { 39 Edge & e = edges[G[x][i]]; 40 if (!vis[e.to] && e.cap > e.flow) { 41 vis[e.to] = 1; 42 d[e.to] = d[x] + 1; 43 Q.push(e.to); 44 } 45 } 46 } 47 return vis[t]; 48 } 49 int DFS(int x, int a) { 50 if (x == t || a == 0) 51 return a; 52 int flow = 0, f; 53 for (int &i = cur[x]; i < G[x].size(); i++) { 54 Edge & e = edges[G[x][i]]; 55 if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) { 56 e.flow += f; 57 edges[G[x][i] ^ 1].flow -= f; 58 flow += f; 59 a -= f; 60 if (a == 0) 61 break; 62 } 63 } 64 return flow; 65 } 66 int Maxflow(int s, int t) { 67 this->s = s, this->t = t; 68 int flow = 0; 69 while (BFS()) { 70 memset(cur, 0, sizeof(cur)); 71 flow += DFS(s, INF); 72 } 73 return flow; 74 } 75 }Men; 76 int main() { 77 int n, kase = 0; 78 while (scanf("%d", &n) && n) { 79 int s, t, c, u, v, w; 80 Men.init(); 81 scanf("%d%d%d", &s, &t, &c); 82 REP(i, 0, c) { 83 scanf("%d%d%d", &u, &v, &w); 84 Men.AddEdge(u, v, w); 85 Men.AddEdge(v, u, w); 86 } 87 printf("Network %d The bandwidth is %d. ", ++kase, Men.Maxflow(s, t)); 88 } 89 return 0; 90 }
uva10801
题意:
一个人在大楼的0楼,大楼最多到99层。有n部电梯,每部电梯有可到达的楼层,每个电梯移动一层的时间为T[i]秒。换电梯的时间为60秒。
给你一个楼层,问你电梯到这个楼层的最短路径。
解法:
很容易看出是一个最短路问题,关键在于如何建图,
首先我们分析一下我们很容易想到把楼层当作点把时间当左边,但是有一个问题由于它涉及楼层中换电梯所以这样做的话我们就无法计算换电梯的时间,所以我的方法是把一个楼层拆成n个点(这样做的前提是在这道题中n比较小<=5)分别表示从哪一个电梯下来的。然后再把相同楼层的点之间加一条长度为60的边。
这样再通过执行n次Dijkstra算法去最小值得出答案。(或者直接Floyd)
1 #include<bits/stdc++.h> 2 #define REP(i, a, b) for(int i = (a); i < (b); i++) 3 #define MEM(a,x) memset(a,x,sizeof(a)) 4 #define INF 0x3f3f3f3f 5 #define MAXN 100+10 6 using namespace std; 7 int t[MAXN], num[MAXN]; 8 int g[MAXN][MAXN]; 9 10 void AddEdge(int i, int j, int s) { 11 g[i][j] = g[j][i] = min(min(g[i][j], g[j][i]), abs(i - j)*s); 12 return; 13 } 14 15 int main() { 16 int n, k; 17 while (scanf("%d%d", &n, &k) != EOF) { 18 MEM(g, INF); 19 REP(i, 0, n)scanf("%d", &t[i]); 20 int UP = -1; 21 REP(i, 0, n) { 22 char ch = ‘