Hdu 3472 HS BDC

来源:互联网 发布:java 判断文件大小 编辑:程序博客网 时间:2024/04/29 04:49

大意:求混合图是否存在欧拉路径。

思路:欧拉路径?什么情况下存在欧拉路径?

(1)、无向图中存在欧拉路径的条件:每个点的度数均为偶数或者有且仅有2个度数为奇数的点。
(2)、有向图中存在欧拉路径的条件:除了2个点外,其余的点入度=出度,且在这2个点中,一个点的入度比出度大1,另一个出度比入度大1。

(3)、由于我们只会混合图的欧拉回路,不会混合图的欧拉路径,于是我们将该问题转换为混合图的欧拉回路,怎么转换呢?找到出入度为奇数的两个点,一个起点,一个终点,从终点向起点连容量为1边的即可。

如果图不连通呢?对,先判是否连通,如果连通再判断图中出入度差dif的值为奇数的有几个,如果是0个,跳过,如果2个,执行(3),然后根据解一般混合图的欧拉回路的方法建图求解即可,这道题的关键在于“化归”思想的运用。

题目的大概思路也出来了,先判连通,可用并查集或者DFS,然后找出入度差为奇数的点,最后根据解一般混合图的欧拉回路算法求解即可。

#include <iostream>#include <cstdlib>#include <cstring>#include <cstdio>using namespace std;const int MAXN = 101;const int MAXM = 20100;const int INF = 0x3f3f3f3f;struct Edge{    int v, f;    int next;}edge[MAXM];int cnt;int n, m;int s, t;int totFlow;int tt;int first[MAXN], level[MAXN];int ind[MAXN], outd[MAXN];int q[MAXN];int vis[MAXN];int p[MAXN], rank[MAXN];char str[MAXN];void init(){    cnt = 0;    totFlow = 0;    memset(first, -1, sizeof(first));    memset(ind, 0, sizeof(ind));    memset(outd, 0, sizeof(outd));    memset(vis, 0, sizeof(vis));}void UFset(){    for(int i = 1; i <= 26; i++) p[i] = i;    memset(rank, 0, sizeof(rank));}int find(int x){    return p[x] == x? x : p[x] = find(p[x]);}void Union(int x, int y){    x = find(x);    y = find(y);    if(x == y) return ;    if(rank[x] > rank[y])    {        p[y] = x;    }    else    {        p[x] = y;        if(rank[x] == rank[y]) rank[y]++;    }}void read_graph(int u, int v, int f){    edge[cnt].v = v, edge[cnt].f = f;    edge[cnt].next = first[u], first[u] = cnt++;    edge[cnt].v = u, edge[cnt].f = 0;    edge[cnt].next = first[v], first[v] = cnt++;}int bfs(int s, int t){    memset(level, 0, sizeof(level));    level[s] = 1;    int front = 0, rear = 1;    q[front] = s;    while(front < rear)    {        int x = q[front++];        if(x == t) return 1;        for(int e = first[x]; e != -1; e = edge[e].next)        {            int v = edge[e].v, f = edge[e].f;            if(!level[v] && f)            {                level[v] = level[x] + 1;                q[rear++] = v;            }        }    }    return 0;}int dfs(int u, int maxf, int t){    if(u == t) return maxf;    int ret = 0;    for(int e = first[u]; e != -1; e = edge[e].next)    {        int v = edge[e].v, f = edge[e].f;        if(level[v] == level[u] + 1 && f)        {            int Min = min(maxf-ret, f);            f = dfs(v, Min, t);            edge[e].f -= f;            edge[e^1].f += f;            ret += f;            if(ret == maxf) return ret;        }    }    return ret;}int Dinic(int s, int t){    int ans = 0;    while(bfs(s, t)) ans += dfs(s, INF, t);    return ans;}void read_case(){init();UFset();int n;scanf("%d", &n);while(n--){int flag;scanf("%s %d", str, &flag);int u = str[0]-'a'+1, v = str[strlen(str)-1]-'a'+1;if(flag) read_graph(u, v, 1);outd[u]++, ind[v]++;Union(u, v);vis[u] = vis[v] = 1;}}int Check() //判连通性 {for(int i = 1; i <= 26; i++){for(int j = i+1; j <= 26; j++){if(vis[j] && vis[i]){if(find(i) != find(j)) return 0;}}}return 1;}int build(){read_case();s = 0, t = 27;if(!Check()) return 0;int tot = 0;int u = 0, v = 0;for(int i = 1; i <= 26; i++) if(vis[i]) //存在0个或者2个入度为奇数的点,说明存在欧拉路径。 {int dif = outd[i]-ind[i];if(dif%2 == 1 || dif%2 == -1){tot++;if(dif > 0) u = i; //起点 if(dif < 0) v = i; //终点 }}if(tot == 0 || (tot == 2 && u && v)){if(tot == 2) read_graph(v, u, 1); //若有两个度数为奇数的点,假设存在欧拉路径,添加一条容量为1的边,构成欧拉回路,不影响结果。 }else return 0;for(int i = 1; i <= 26; i++) if(vis[i]){int dif = outd[i]-ind[i];if(dif > 0){read_graph(s, i, dif/2);totFlow += dif/2;}else read_graph(i, t, -dif/2);}return 1;}void solve(){int flag = build();int ans = Dinic(s, t);printf("Case %d: ", tt);if(!flag) printf("Poor boy!\n");else if(ans >= totFlow) printf("Well done!\n");else printf("Poor boy!\n");}int main(){    int T, times = 0;    scanf("%d", &T);    for(tt = 1; tt <= T; tt++)    {        solve();    }    return 0;}


原创粉丝点击