hdu 3472 HS BDC

题目链接

很容易看出是混合图的欧拉路径问题,注意不是欧拉回路,这是有很大区别的。

上一篇博文介绍用最大流解决混合图的欧拉回路问题,这里的混合图的欧拉路径问题,采用化归的思想,转化为欧拉回路求解。如果没有入度+出度是奇数的点,那么不需要化归;如果这样的点有两个,那么将这两个点随意连一条边,容量为1,转化为欧拉回路问题;如果这样的点不是0或2个,证明没有欧拉路径,至此就解决了本题。

AC代码:

#include <math.h>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>

using namespace std;

const int MAX = 5010;
const int INF = 0x3f3f3f3f;

int S,T,s1,s2,totflow;
int I[30],O[30];
int dis[30],Q[30],h,t;
int cnt,head[30],father[30],vis[30];
struct edge{
    int v,c,next;
}node[MAX];

void Init(){
    cnt = 0;
    totflow = 0;
    for(int i=1; i<=26; i++) father[i] = i;
    memset(I, 0, sizeof(I));
    memset(O, 0, sizeof(O));
    memset(vis, 0, sizeof(vis));
    memset(head, -1, sizeof(head));
}

int Find(int x){
    if(x != father[x])
        father[x] = Find(father[x]);
    return father[x];
}

void addedge(int u, int v, int c){
    node[cnt].v = v;
    node[cnt].c = c;
    node[cnt].next = head[u];
    head[u] = cnt++;
}

bool is_connect(){//并查集判断图是否连通
    int tmp = 0;
    for(int i=1; i<=26; i++){
        if(!vis[i]) continue;
        if(father[i] == i) tmp++;
    }
    if(tmp > 1) return false;
    return true;
}

bool buildflow(){
    s1 = -1, s2 = -1;
    int tmp = 0;
    for(int i=1; i<=26; i++){
        if(!vis[i]) continue;
        if((O[i] + I[i])&1){
            tmp++;
            if(s1 != -1) s2 = i;
            else s1 = i;
        }
        if(O[i] > I[i]){
            int c = (O[i]-I[i]) >> 1;
            addedge(S, i, c);
            addedge(i, S, 0);
            totflow += c;
        }   
        else{
            int c = (I[i] - O[i]) >> 1;
            addedge(i, T, c);
            addedge(T, i, 0);
        }
    }
    if(tmp != 0 && tmp != 2) return false;
    if(tmp == 2){//化归的操作
        O[s1]++;
        I[s2]++;
        addedge(s1, s2, 1);
        addedge(s2, s1, 0);
    }
    return true;
}

bool BFS(){//构建层次图
    memset(dis, -1, sizeof(dis));
    Q[1] = S, h = 0, t = 1, dis[S] = 0;
    while(h < t){
        int u = Q[++h];
        for(int i=head[u]; i!=-1; i=node[i].next){
            int v = node[i].v;
            if(node[i].c > 0 && dis[v] == -1){
                dis[v] = dis[u] + 1;
                Q[++t] = v;
                if(v == T) return true;
            }
        }
    }
    return false;
}

int DFS(int id, int minflow){//增广过程
    if(id == T) return minflow;
    int a = 0;
    for(int i=head[id]; i!=-1; i=node[i].next){
        int v = node[i].v;
        if(node[i].c > 0 && dis[v] == dis[id] + 1 
            && (a = DFS(v, min(node[i].c, minflow)))){
            node[i].c -= a;
            node[i^1].c += a;
            return a;
        }
    }
    return 0;
}

int Dinic(){
    int tmp, ans = 0;
    while(BFS()){
        while(tmp = DFS(S, INF)) ans += tmp;
    }
    return ans;
}

int main(){
    int cas,t=0;
    scanf("%d",&cas);
    while(cas--){
        int n,d;
        scanf("%d",&n);
        char str[25];
        Init();
        for(int i=0; i<n; i++){
            scanf("%s",str);
            scanf("%d",&d);
            int l = strlen(str);
            int u = str[0]-'a'+1, v = str[l-1]-'a'+1;
            father[Find(u)] = Find(v);
            vis[v] = vis[u] = 1;
            O[u]++, I[v]++;
            if(d){
                addedge(u, v, 1);
                addedge(v, u, 0);
            }
        }
        printf("Case %d: ",++t);
        if(!is_connect()) {
            puts("Poor boy!"); 
            continue;
        }
        S = 0, T = 27;//设置源点 汇点
        int flag = buildflow(), ans = Dinic();
        if(!flag) {
            puts("Poor boy!"); 
            continue;
        }
        if(ans == totflow) puts("Well done!");//满流
        else puts("Poor boy!"); 
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值