解题报告 之 POJ1637 Sightseeing tour

来源:互联网 发布:java servlet是什么 编辑:程序博客网 时间:2024/05/08 13:06

解题报告 之 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

45 82 1 01 3 04 1 11 5 05 4 13 4 04 2 12 2 04 41 2 12 3 03 4 01 4 13 31 2 02 3 03 2 03 41 2 02 3 11 2 03 2 0

Sample Output

possibleimpossibleimpossiblepossible


题目大意:有n个城市,m条街道,可能是单向也可能是双向。问该图中存不存在从某一点出发的欧拉回路?


分析:首先明确一下欧拉回路的概念:从某点出发,每一条边都经过且只经过一次,包括双向边也只能走一次,而不是拆成两条边,所以不能直接当做单纯的有向边或者无向边的欧拉来做。故这种问题称为混合图的欧拉回路,用最大流来做。其实很明显这道题的难点在于怎么确定有向边到底用哪个方向?


如果有欧拉回路:无论有向边朝那个方向,有一点不会变,那就是某一个点的出边和入边只差是偶数,为什么呢?因为相当于在这条欧拉回路修改了一些有向边的方向。所以修改有向边时,一个节点出边+1,入边-1;而对应的节点入边+1,出边-1,但出入边只差从0变到+-2,即+-2n。所以最后一定是差为偶数。所以我们先跑一次欧拉判断,把不是偶数的情况直接输出impossible。


接下来处理都是偶数的情况。此时有一个巧思。如果一个节点入边大于出边,那么我们将这个差值/2看做这个点周围需要向外转向的条数。反之,如果出边大于入边,差值/2表示这个点需要向内转向的条数。那么就可以看做是流量负载了。对于所有入边大于出边的点,从超级源点拉一条边到该点,负载(in-out)/2,反之,从该点拉一条边到超级汇点,负载(out-in)/2。 对于所有无向边,我们从入点向出点拉一条负载为1的边(如果有k条重编则负载为k),意义是我们可以反向的资本。最后跑最大流判断是否等于总差值flow(跑欧拉检测是顺便统计)即可。


上代码:

#include<iostream>#include<algorithm>#include<cstdio>#include<queue>#include<cstring>using namespace std;const int MAXN = 500;const int MAXM = 4000;const int INF = 0x3f3f3f3f;struct Edge{int to, next, cap;};Edge edge[MAXM];int level[MAXN];int head[MAXN];int ass[MAXN][MAXN];int in[MAXN], out[MAXN];int src, des, cnt,flow;void addedge(int from,int to,int cap){edge[cnt].to = to;edge[cnt].cap=cap;edge[cnt].next = head[from];head[from] = cnt++;edge[cnt].to = from;edge[cnt].cap=0;edge[cnt].next = head[to];head[to] = cnt++;}int bfs(){queue<int> q;while (!q.empty())q.pop();memset(level, -1, sizeof level);level[src] = 0;q.push(src);while (!q.empty()){int u = q.front();q.pop();for (int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].to;if (edge[i].cap > 0 && level[v] == -1){level[v] = level[u] + 1;q.push(v);}}}return level[des] != -1;}int dfs(int u, int f){if (u == des) return f;int tem;for (int i = head[u]; i != -1; i = edge[i].next){int v = edge[i].to;if (edge[i].cap > 0 && level[v] == level[u] + 1){tem = dfs(v, min(f, edge[i].cap));if (tem > 0){edge[i].cap -= tem;edge[i ^ 1].cap += tem;return tem;}}}level[u] = -1;return 0;}bool Euler(int n){flow = 0;for (int i = 1; i <= n; i++){if (in[i] - out[i] > 0) flow += (in[i] - out[i])/2;if ((in[i] - out[i]) % 2 != 0)return false;}return true;}int Dinic(){int ans = 0, tem;while (bfs()){while (tem = dfs(src, INF)){ans += tem;}}return ans;}int main(){int kase;int n, m;cin >> kase;while (kase--){memset(in, 0, sizeof in);memset(out, 0, sizeof out);memset(ass, 0, sizeof ass);scanf("%d%d", &n, &m);src = 0; des = n + 1;for (int i = 1; i <= m; i++){int a, b, c;scanf("%d%d%d", &a, &b, &c);out[a]++; in[b]++;if (c == 0) ass[a][b]++;}if (!Euler(n)){cout << "impossible" << endl;continue;}cnt = 0;memset(head, -1, sizeof head);for (int i = 1; i <= n; i++){if (in[i] > out[i])  addedge(src, i, (in[i] - out[i])/2);else if (out[i] > in[i]) addedge(i, des, (out[i] - in[i])/2);for (int j = 1; j <= n; j++){if (ass[i][j])addedge(j, i, ass[i][j]);}}if (Dinic() == flow)cout << "possible" << endl;elsecout << "impossible" << endl;}return 0;}

今天心情不太好。怀疑自己是不是有天赋。我觉得还是自己水平不行,不然也不至于那么悲惨。可能是太浮躁了没有静下心来搞,也可能是什么都想搞,结果什么都搞不好。其实我更愿意相信是我的考试策略不对,但事实有摆在那里,容不得辩驳。罢了,不管中途结果如何也只能继续前行。A ship voyage's true paths never show before reaching the destination! 虽然没能去北京见偶像,但是还是衷心祝愿两位队友北京加油!!


0 0
原创粉丝点击