【POJ1637】Sightseeing tour

Description

The city executive board in Lund wants to construct a sightseeing tour by bus in Lund, so that tourists can see every corner of the beautiful city. They want to construct the tour so that every street in the city is visited exactly once. The bus should also start and end at the same junction. As in any city, the streets are either one-way or two-way, traffic rules that must be obeyed by the tour bus. Help the executive board and determine if it‘s possible to construct a sightseeing tour under these constraints.

Input

On the first line of the input is a single positive integer n, telling the number of test scenarios to follow. Each scenario begins with a line containing two positive integers m and s, 1 <= m <= 200,1 <= s <= 1000 being the number of junctions and streets, respectively. The following s lines contain the streets. Each street is described with three integers, xi, yi, and di, 1 <= xi,yi <= m, 0 <= di <= 1, where xi and yi are the junctions connected by a street. If di=1, then the street is a one-way street (going from xi to yi), otherwise it‘s a two-way street. You may assume that there exists a junction from where all other junctions can be reached.

Output

For each scenario, output one line containing the text "possible" or "impossible", whether or not it‘s possible to construct a sightseeing tour.

Sample Input

4
5 8
2 1 0
1 3 0
4 1 1
1 5 0
5 4 1
3 4 0
4 2 1
2 2 0
4 4
1 2 1
2 3 0
3 4 0
1 4 1
3 3
1 2 0
2 3 0
3 2 0
3 4
1 2 0
2 3 1
1 2 0
3 2 0

Sample Output

possible
impossible
impossible
possible

题意:

  给出一张既有单向边又有双向边的图,给其中的双向边定向之后使得图构成欧拉回路,问是否存在可行方案。

分析:

对于无向边,我们不知道方向,就随便定向,然后再想想怎么修改。

定完向之后,求所有点的出度与入度,如果任意一个点出度和入度的差为奇数,那么图将无法构成欧拉回路。

(先假设,一个点的出度和入度分别为out和in,如果出度和入度的差|out-in|为奇数,这时有a条连向这个点的边改变了方向,b条从这个点向外连的边改变了方向,那么它的入度就变为了in-a+b,出度变为了out-b+a,出度和入度的差|out-b+a-in+a-b|=|out-in+2a-2b|还是奇数,所以无论如何将边重定向,图都无法构成欧拉回路。)

对于图中的一个点,如果in>out,则说明需要有(in - out)/2条出边需要改变方向,如果in<out,则说明需要有(out - in)/2条入边需要改变方向。而对于无向边(u,v),定义其方向为u->v,那么它将有可能被改为v->u。

剩下的问题用最大流就能解决,对于每个in>out的节点,从源向这个点连一条流量为(in-out)/2的边,对于每个in<out的点,从这个点向汇连一条流量为(out-in)/2的边。而对于每条被定向为u->v的无向边,从v向u连接一条流量为1的边,这条边被流过则说明(u,v)被改变了方向。

跑一遍最大流,如果最大的流量等于与汇相连的边的流量总和,则说明在将一些边重定向后可以满足所有点出度与入度相等,即可以构成欧拉回路。

代码:

  1 #include <cstdio>
  2 #include <cstring>
  3
  4 const int maxn = 300;
  5 const int maxm = 3000;
  6
  7 int et[maxm], ep[maxm], ef[maxm];
  8 int last[maxn], en;
  9 int p1, p2, dir;
 10 int t, n, m, sta, end, ans, ind[maxn];
 11
 12 inline void insert(int from, int to, int flow)
 13 {
 14     en++;
 15     et[en] = to;
 16     ef[en] = flow;
 17     ep[en] = last[from];
 18     last[from] = en;
 19     en++;
 20     et[en] = from;
 21     ef[en] = 0;
 22     ep[en] = last[to];
 23     last[to] = en;
 24 }
 25
 26 inline int min(int a, int b)
 27 {
 28     return a < b ? a : b;
 29 }
 30
 31 int gap[maxn], dis[maxn], cur[maxn];
 32
 33 int sap(int now, int flow)
 34 {
 35     if (now == end)
 36     {
 37         return flow;
 38     }
 39     int ret = 0, tmp;
 40     for (int e = cur[now]; e; cur[now] = e = ep[e])
 41     {
 42         if (et[e] > 0 && dis[now] == dis[et[e]] + 1)
 43         {
 44             tmp = sap(et[e], min(flow - ret, ef[e]));
 45             ret += tmp;
 46             ef[e] -= tmp;
 47             ef[e ^ 1] += tmp;
 48             if (ret == flow)
 49             {
 50                 return ret;
 51             }
 52         }
 53     }
 54     cur[now] = last[now];
 55     if (--gap[dis[now]] <= 0)
 56     {
 57         dis[sta] = end + 1;
 58     }
 59     ++gap[++dis[now]];
 60     return ret;
 61 }
 62
 63 int maxflow()
 64 {
 65     memset(gap, 0, sizeof(gap));
 66     memset(dis, 0, sizeof(dis));
 67     int flow = 0;
 68     gap[0] = end;
 69     for (int i = 1; i <= end; i++)
 70     {
 71         cur[i] = last[i];
 72     }
 73     while (dis[sta] <= end)
 74     {
 75         flow += sap(sta, 2147483647);
 76     }
 77     return flow;
 78 }
 79
 80 int main()
 81 {
 82     scanf("%d", &t);
 83     while (t--)
 84     {
 85         memset(last, 0, sizeof(last));
 86         memset(ind, 0, sizeof(ind));
 87         en = 1;
 88         ans = 0;
 89         scanf("%d%d", &n, &m);
 90         sta = n + 1;
 91         end = sta + 1;
 92         for (int i = 0; i < m; i++)
 93         {
 94             scanf("%d%d%d", &p1, &p2, &dir);
 95             ind[p1]--;
 96             ind[p2]++;
 97             if (!dir)
 98             {
 99                 insert(p2, p1, 1);
100             }
101         }
102         bool flag = 1;
103         for (int i = 1; i <= n; i++)
104         {
105             if (ind[i] % 2 > 0)
106             {
107                 flag = 0;
108                 break;
109             }
110             if (ind[i] > 0)
111             {
112                 insert(sta, i, ind[i] / 2);
113             }
114             if (ind[i] < 0)
115             {
116                 insert(i, end, -ind[i] / 2);
117                 ans += -ind[i] / 2;
118             }
119         }
120         if (flag == 0)
121         {
122             puts("impossible");
123         }
124         else
125         {
126             puts(maxflow() == ans ? "possible" : "impossible");
127         }
128     }
129 }
时间: 2024-07-30 00:22:21

【POJ1637】Sightseeing tour的相关文章

【POJ1637】Sightseeing tour 混合图求欧拉回路存在性 网络流、

题意:多组数据,最后的0/1表示0无向1有向. 问是否存在欧拉回路. 题解:无向边给它任意定个向. 首先欧拉回路中点入度=出度. 然后发现每个无向边如果修改个方向,原来的入点的入度+1,出度-1,出点反之. 然后我们不妨对入度和出度不同的点跟源汇中之一连边,容量为入出度差一半(每改一条边差-2) 然后原来的无向边联系图中各点,容量1,最后check if(maxflow==sum差/4). 这都没看懂的弱菜们不妨出度多的连源,入度多的连汇,容量为入出度差一半,然后按无向边的定向给它在网络流图中定

【POJ】【1637】Sightseeing tour

网络流/最大流 愚人节快乐XD 这题是给一个混合图(既有有向边又有无向边),让你判断是否有欧拉回路…… 我们知道如果一个[连通]图中每个节点都满足[入度=出度]那么就一定有欧拉回路…… 那么每条边都可以贡献一个出度出来,对于一条边u->v: 连S->edge cap=1; 如果是有向边,就连 edge->v cap=1; 否则(无向边)连edge->u cap=1, edge->v cap=1; 然后每个点的总度数我们是知道的……那么它最后的[出度]就等于 总度数/2.(这个

【POJ3621】Sightseeing Cows 分数规划

[POJ3621]Sightseeing Cows 题意:在给定的一个图上寻找一个环路,使得总欢乐值(经过的点权值之和)/ 总时间(经过的边权值之和)最大. 题解:显然是分数规划,二分答案ans,将每条边的权值变成(ans*边权-2*起始点点权),然后我们希望找出一个环,使得环上的总边权<0 (一开始我把题意理解错了,题中给的是单向边,我把它当成是双向边+每条边只能走一次了~,想出一堆做法都接连pass掉) 然后就直接用SPFA判负环就好了嘛!由于原图不一定联通,所以一开始就把所有点都入队就完事

【POJ3621】Sightseeing Cows

Sightseeing Cows Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8331   Accepted: 2791 Description Farmer John has decided to reward his cows for their hard work by taking them on a tour of the big city! The cows must decide how best to

【CF666B】World Tour

题意:给你一张有向图,叫你给出四个点的序列a,b,c,d,使得这四个点依次间的最短路之和最大.(4 ≤ n ≤ 3000, 3 ≤ m ≤ 5000) 思路:O(n4)可用来对拍 我们需要O(n2)级别的算法 若枚举c,d,预处理出x到b比较远的3个x,d到y比较远的3个y,时间复杂度O(9n2) 为什么是3个而不是2个? abc已枚举,若d的备选是ab就要GG,所以应该多一个备用,也就是三个点 1 var c,d:array[1..3000,1..3,1..2]of longint; 2 he

【SPOJ】【1825】Free Tour 2

点分治 点分治的例题2(本题代码结果为TLE……) 强烈谴责卡时限QAQ,T了无数次啊无数次…… 不过在N次的静态查错中倒是加深了对点分治的理解……也算因祸得福吧(自我安慰一下) 1 //SPOJ 1825 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<iostream> 6 #include<algorithm> 7 #define rep(i,n)

【bzoj3060】[Poi2012]Tour de Byteotia 并查集

题目描述 给定一个n个点m条边的无向图,问最少删掉多少条边能使得编号小于等于k的点都不在环上. 输入 第一行三个整数n,m,k: 接下来m行每行两个整数ai,bi,表示ai和bi之间有一条无向边. 输出 一个整数,表示最少的删边数量. 样例输入 11 13 5 1 2 1 3 1 5 3 5 2 8 4 11 7 11 6 10 6 9 2 3 8 9 5 9 9 10 样例输出 3 题解 并查集 先把不包含编号小于等于k的点的边连上,用并查集维护图的连通性.易知如果删除这些边则一定不是最优解,

【POJ1734】Sightseeing Trip 无向图最小环

题目大意:给定一个 N 个顶点的无向图,边有边权,如果存在,求出该无向图的最小环,即:边权和最小的环,并输出路径. 题解:由于无向图,且节点数较少,考虑 Floyd 算法,在最外层刚开始遍历到第 K 号节点时,\(d[i][j]\) 中记录着经过前 k-1 个点,从 i 到 j 的最短距离.因此,可以依次考虑每一个结构:\(\{d[i][j]+G[i][k]+G[k][j] \}\),这便是一个环形结构,每次更新答案贡献即可. 至于路径输出,\(get\_path(int\ i,int\ j)\

【POJ1734】Sightseeing trip

题目链接:https://www.acwing.com/problem/content/346/ 题目大意:确定无向带权图上至少包含 3 个节点的最小环 solution 一道无向图上的最小环问题 , 考虑 \(Floyd\) , 设 \(i\) 到 \(j\) 间的道路长为 \(f[i][j]\) , 最短路径长 \(g[i][j]\) , 若每次 \(Floyd\) 最外层 遍历到 \(k\) 时 , \(g[i][j]\) 决定了 \(i\) 到 \(j\) 间经过节点编号不超过 \(k\