现在的位置: 首页 > 综合 > 正文

Hdu 3472 HS BDC

2019年04月08日 ⁄ 综合 ⁄ 共 2938字 ⁄ 字号 评论关闭

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

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

(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;
}

抱歉!评论已关闭.