HDU 3472 HS BDC(混合欧拉图(使用最大流))模板

HS BDC

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)

Total Submission(s): 980    Accepted Submission(s): 398

Problem Description

IELTS is around the corner! love8909 has registered for the exam, but he still hasn’t got prepared. Now he decides to take actions. But when he takes out the New Oriental IELTS Vocabulary, he finds there are so many words. But love8909
doesn’t get scared, because he has got a special skill. If he can make a list with some meaningful words, he will quickly remember these words and will not forget them. If the last letter of some word Wa is the same as the first letter of some word Wb, then
you can connect these two words and make a list of two words. If you can connect a word to a list, you will make a longer list.

While love8909 is making the list, he finds that some words are still meaningful words if you reverse them. For example, if you reverse the word “pat”, you will get another meaningful word “tap”.

After scanning the vocabulary, love8909 has found there are N words, some of them are meaningful if reversed, while others are not. Now he wonders whether he can remember all these words using his special skill.

The N-word list must contain every word once and only once.

Input

An integer T (T <= 50) comes on the first line, indicating the number of test cases.

On the first line of each test cases is an integer N (N <= 1000), telling you that there are N words that love8909 wants to remember. Then comes N lines. Each of the following N lines has this format: word type. Word will be a string with only ‘a’~’z’, and
type will be 0(not meaningful when reversed) or 1(meaningful when reversed). The length of each word is guaranteed to be less than 20.

Output

The format of the output is like “Case t: s”, t is the number of the test cases, starting from 1, and s is a string.

For each test case, if love8909 can remember all the words, s will be “Well done!”, otherwise it’s “Poor boy!”

Sample Input

3
6
aloha 0
arachnid 0
dog 0
gopher 0
tar 1
tiger 0
3
thee 1
earn 0
nothing 0
2
pat 1
acm 0

Sample Output

Case 1: Well done!
Case 2: Well done!
Case 3: Poor boy!

Hint

In the first case, the word “tar” is still meaningful when reversed, and love8909 can make a list as “aloha-arachnid-dog-gopher-rat-tiger”.
 In the second case, the word “thee” is still meaningful when reversed, and love8909 can make a list as “thee-earn-nothing”. In the third case,
no lists can be created.

Author

allenlowesy

Source

2010 ACM-ICPC Multi-University
Training Contest(4)——Host by UESTC

题意:给n个字符串,0:表示首尾的一个字符不能对换,1:表示可以对换。如果一个字符串的尾字符与另一个字符串的首字符相同则可以接在一起,问能否把所有的字符串接成一个串。

解题:如果把一个字符串的道字符看成起点u,尾字符看成终点v,对与0:则是一个有向边,对于1 则是双向边。这题就是一笔画成,但是分有向和无向,所以是混合欧拉图(1)首先,判断所有出现的点是不是在一个连通块。(2)顶点的总度数为奇度顶点的个数是否有0个或恰好有2个。(3)建图,用最大流,是否满流来判断是否可以。

#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;
#define captype int

const int MAXN = 100010;   //点的总数
const int MAXM = 400010;    //边的总数
const int INF = 1<<30;
struct EDG{
    int to,next;
    captype cap,flow;
} edg[MAXM];
int eid,head[MAXN];
int gap[MAXN];  //每种距离(或可认为是高度)点的个数
int dis[MAXN];  //每个点到终点eNode 的最短距离
int cur[MAXN];  //cur[u] 表示从u点出发可流经 cur[u] 号边
int pre[MAXN];

void init(){
    eid=0;
    memset(head,-1,sizeof(head));
}
//有向边 三个参数,无向边4个参数
void addEdg(int u,int v,captype c,captype rc=0){
    edg[eid].to=v; edg[eid].next=head[u];
    edg[eid].cap=c; edg[eid].flow=0; head[u]=eid++;

    edg[eid].to=u; edg[eid].next=head[v];
    edg[eid].cap=rc; edg[eid].flow=0; head[v]=eid++;
}
captype maxFlow_sap(int sNode,int eNode, int n){//n是包括源点和汇点的总点个数,这个一定要注意
    memset(gap,0,sizeof(gap));
    memset(dis,0,sizeof(dis));
    memcpy(cur,head,sizeof(head));
    pre[sNode] = -1;
    gap[0]=n;
    captype ans=0;  //最大流
    int u=sNode;
    while(dis[sNode]<n){   //判断从sNode点有没有流向下一个相邻的点
        if(u==eNode){   //找到一条可增流的路
            captype Min=INF ;
            int inser;
            for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to])    //从这条可增流的路找到最多可增的流量Min
            if(Min>edg[i].cap-edg[i].flow){
                Min=edg[i].cap-edg[i].flow;
                inser=i;
            }
            for(int i=pre[u]; i!=-1; i=pre[edg[i^1].to]){
                edg[i].flow+=Min;
                edg[i^1].flow-=Min;  //可回流的边的流量
            }
            ans+=Min;
            u=edg[inser^1].to;
            continue;
        }
        bool flag = false;  //判断能否从u点出发可往相邻点流
        int v;
        for(int i=cur[u]; i!=-1; i=edg[i].next){
            v=edg[i].to;
            if(edg[i].cap-edg[i].flow>0 && dis[u]==dis[v]+1){
                flag=true;
                cur[u]=pre[v]=i;
                break;
            }
        }
        if(flag){
            u=v;
            continue;
        }
        //如果上面没有找到一个可流的相邻点,则改变出发点u的距离(也可认为是高度)为相邻可流点的最小距离+1
        int Mind= n;
        for(int i=head[u]; i!=-1; i=edg[i].next)
        if(edg[i].cap-edg[i].flow>0 && Mind>dis[edg[i].to]){
            Mind=dis[edg[i].to];
            cur[u]=i;
        }
        gap[dis[u]]--;
        if(gap[dis[u]]==0) return ans;  //当dis[u]这种距离的点没有了,也就不可能从源点出发找到一条增广流路径
                                        //因为汇点到当前点的距离只有一种,那么从源点到汇点必然经过当前点,然而当前点又没能找到可流向的点,那么必然断流
        dis[u]=Mind+1;//如果找到一个可流的相邻点,则距离为相邻点距离+1,如果找不到,则为n+1
        gap[dis[u]]++;
        if(u!=sNode) u=edg[pre[u]^1].to;  //退一条边
    }
    return ans;
}
int fath[MAXN];
int findfath(int x){
    if(x!=fath[x])
        fath[x]=findfath(fath[x]);
    return fath[x];
}
void linke(int x,int y){
    x=findfath(x);
    y=findfath(y);
    fath[x]=y;
}
int main()
{
    int T,_cas=0,n, p ,in[50],out[50];
    char s[50];
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        init();
        memset(in,0,sizeof(in));
        memset(out,0,sizeof(out));
        for(int i=0; i<=26; i++)
            fath[i]=i;

        int flag = 1 , root =0;
        for(int i=0; i<n; i++){
            scanf("%s%d",s,&p);
            int u=s[0]-'a';
            int v=s[strlen(s)-1]-'a';
            out[u]++; in[v]++;
            root=u;
            if(p==1) addEdg(u,v,1);    //双向的则建一条容量为1的边
            linke(u,v);
        }
        root=findfath(root);
        int cnt=0 , u=-1,v=-1;
        for(int i=0; i<26 ; i++)
        if(in[i]||out[i]){
            if(findfath(i)!=root){
                flag=0; break;
            }
            if((in[i]+out[i])&1){
                cnt++;
                if(u==-1)
                    u=i;
                else v=i;
            }
        }
        if(cnt!=0&&cnt!=2) flag=0;
        if(flag==0){
            printf("Case %d: Poor boy!\n",++_cas); continue;
        }
        if(cnt==2){
            out[u]++; in[v]++;
            addEdg(u,v,1);  //构造成欧拉环,添加的是双向边
        }
        int s=26 , t = 27;
        for(int i=0; i<26; i++){
            if(out[i]>in[i])
                addEdg(s,i,(out[i]-in[i])/2);
            else if(out[i]<in[i])
                addEdg(i,t,(in[i]-out[i])/2);
        }
        maxFlow_sap( s , t , t+1);
        for(int i=head[s]; i!=-1; i=edg[i].next)//判断满流
        if(edg[i].cap>0 && edg[i].cap>edg[i].flow){
            flag=0; break;
        }

        if(flag) printf("Case %d: Well done!\n",++_cas);
        else  printf("Case %d: Poor boy!\n",++_cas);
    }
}
时间: 2024-10-25 06:10:38

HDU 3472 HS BDC(混合欧拉图(使用最大流))模板的相关文章

hdu 3472 HS BDC 混合欧拉 网络流

题意就是问能否将给定的几个单词全部连接起来,两个单词能连接是当前一个单词的最后一个字母等于后一个单词的首字母.还有一些单词反向也没有关系. 建图,每输入一个单词,只看他的首尾字母,连接一条首字母到尾字母的有向边,如果他可以反向,那么再反向建立一条边,即该边是无向边.然后就是一个混合欧拉了. 还有一个注意的地方,就是可能是欧拉道路,这时只要在添加一条边连接两个奇度节点就好. #include <iostream> #include <cstdio> #include <cstr

hdu 3472 HS BDC(混合路的欧拉路径)

这题是混合路的欧拉路径问题. 1.判断图的连通性,若不连通,无解. 2.给无向边任意定向,计算每个结点入度和出度之差deg[i].deg[i]为奇数的结点个数只能是0个或2个,否则肯定无解. 3.(若存在2个deg[i]为奇数的结点,则在两点连一条流量为1的边,方向任意)设立源点s和汇点t(自己另外定两个点),若某点i入度<出度,连边(s,i,-deg[i]/2),若入度>出度,连边(i,t,deg[i]/2):对于任意定向的无向边(i,j,1). 5.若从S发出的边全部满流,证明存在欧拉回路

hdu3472 HS BDC --- 混合图欧拉回路

讲的很好的资料: 点击打开链接 点击打开链接 #include <iostream> #include <cstdlib> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include &l

HS BDC (hdu 3472 混合图的欧拉回路)

HS BDC Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 974    Accepted Submission(s): 395 Problem Description IELTS is around the corner! love8909 has registered for the exam, but he still hasn

混合图欧拉回路(hdoj3472 HS BDC)

欧拉回路基础知识戳这里 混合图:就是图里面有的边是有向边,有的边是无向边,组成的图叫做混合图. 要判混合图是否满足欧拉回路,首先必须满足欧拉图的条件 1:欧拉回路要求所有点的度数必须都为偶数,欧拉道路要求所有点的度数两个奇数. 2:给无向的边定向,首先任意定向,这些便之间网络流建边from到to容量为1,然后对于当前入度大于出度的点y,说明有d = (入度-出度)/2的边需要变成相反方向,我们这里不进行变向,而是用一个网络流的超级汇点T,给其建边y到T,容量为d. 然后对于当前出度大于入度的点x

hdu 3472 混合图的欧拉路径

HS BDC Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 964    Accepted Submission(s): 390 Problem Description IELTS is around the corner! love8909 has registered for the exam, but he still hasn’

hdu 3081 hdu 3277 hdu 3416 Marriage Match II III IV //最大流的灵活运用

3081 题意: n个女孩选择没有与自己吵过架的男孩有连边(自己的朋友也算,并查集处理),2分图,有些边,求有几种完美匹配(每次匹配每个点都不重复匹配) 我是建二分图后,每次增广一单位,(一次完美匹配),再修改起点还有终点的边流量,继续增广,直到达不到完美匹配为止.网上很多是用二分做的,我觉得没必要...(网上传播跟风真严重...很多人都不是真正懂最大流算法的...) 3277 : 再附加一条件,每个女孩可以最多与k个自己不喜欢的男孩.求有几种完美匹配(同上). 我觉得:求出上题答案,直接ans

HDU 3395 Special Fish 最“大”费用最大流

求最大费用可以将边权取负以转化成求最小费用.然而此时依然不对,因为会优先寻找最大流,但是答案并不一定出现在满流的时候.所以要加一些边(下图中的红边)使其在答案出现时满流.设所有边的流量为1,花费如下图所示.显然最大花费是1001,而没有红边的情况下会得到3. #include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio>

HDU 2544 最短路(我的dijkstra算法模板、SPAFA算法模板)

思路:这道题是基础的最短路径算法,可以拿来试一下自己对3种方法的理解 dijkstra主要是从第一个点开始枚举,每次枚举出当当前最小的路径,然后再以那最小的路径点为起点,求出它到其它未标记点的最短距离 bellman-ford 算法则是假设有向网中有n 个顶点.且不存在负权值回路,从顶点v1 和到顶点v2 如果存在最短路径,则此路径最多有n-1 条边.这是因为如果路径上的边数超过了n-1 条时,必然会重复经过一个顶点,形成回路:而如果这个回路的权值总和为非负时,完全可以去掉这个回路,使得v1到v