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’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!

一道水题,只需注意先判断图的连通性即可,然后就是直接套模板就可以ac

谁要是有闲工夫可以研究一下这两个测试数据

1:

4

a 0

b 0

bc 0

ac 1

2:

4

a 0

b 0

bc 0

ca 1

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include<climits>
#define MAXE 1800
#define MAXP 30
#define Max(a,b) a>b?a:b
#define Min(a,b) a<b?a:b
using namespace std;
struct Edge
{
    int s,t,f,next;
} edge[MAXE];
int head[MAXP];
int cur[MAXP];
int pre[MAXP];
int stack[MAXE];
int used[MAXP];
int fa[MAXP];
int degree[MAXP];
int ent;
int sum;
int n,m,s,t,supers,supert;
int num;
int find(int x)
{
    while(fa[x]!=x)
        x=fa[x];
    return x;
}
void add(int start,int last,int f)
{
    edge[ent].s=start;
    edge[ent].t=last;
    edge[ent].f=f;
    edge[ent].next=head[start];
    head[start]=ent++;
    edge[ent].s=last;
    edge[ent].t=start;
    edge[ent].f=0;
    edge[ent].next=head[last];
    head[last]=ent++;
}
bool bfs(int S,int T)
{
    memset(pre,-1,sizeof(pre));
    pre[S]=0;
    queue<int>q;
    q.push(S);
    while(!q.empty())
    {
        int temp=q.front();
        q.pop();
        for(int i=head[temp]; i!=-1; i=edge[i].next)
        {
            int temp2=edge[i].t;
            if(pre[temp2]==-1&&edge[i].f)
            {
                pre[temp2]=pre[temp]+1;
                q.push(temp2);
            }
        }
    }
    return pre[T]!=-1;
}
int dinic(int start,int last)
{
    int flow=0,now;
    while(bfs(start,last))
    {
        int top=0;
        memcpy(cur,head,sizeof(head));
        int u=start;
        while(1)
        {
            if(u==last)//如果找到终点结束对中间路径进行处理并计算出该流
            {
                int minn=INT_MAX;
                for(int i=0; i<top; i++)
                {
                    if(minn>edge[stack[i]].f)
                    {
                        minn=edge[stack[i]].f;
                        now=i;
                    }
                }
                flow+=minn;
                for(int i=0; i<top; i++)
                {
                    edge[stack[i]].f-=minn;
                    edge[stack[i]^1].f+=minn;
                }
                top=now;
                u=edge[stack[top]].s;
            }
            for(int i=cur[u]; i!=-1; cur[u]=i=edge[i].next) //找出从u点出发能到的边
                if(edge[i].f&&pre[edge[i].t]==pre[u]+1)
                    break;
            if(cur[u]==-1)//如果从该点未找到可行边,将该点标记并回溯
            {
                if(top==0)break;
                pre[u]=-1;
                u=edge[stack[--top]].s;
            }
            else//如果找到了继续运行
            {
                stack[top++]=cur[u];
                u=edge[cur[u]].t;
            }
        }
    }
    return flow;
}
int main()
{
    int cas;
    scanf("%d",&cas);
    for(int times=1;times<=cas;times++)
    {
        memset(head,-1,sizeof(head));
        memset(used,0,sizeof(used));
        memset(degree,0,sizeof(degree));//初始化的过程
        ent=0;
        s=0,t=27;
        scanf("%d",&n);
        char str[25];
        int mark;
        for(int i=1;i<=26;i++)
            fa[i]=i;
        for(int i=1;i<=n;i++)
        {
            scanf("%s%d",str,&mark);
            int len=strlen(str);
            int u=str[0]-‘a‘+1;
            int v=str[len-1]-‘a‘+1;
            used[u]=1;
            used[v]=1;
            if(find(u)!=find(v))
            {
                fa[find(v)]=find(u);//检查图的联通性的过程
            }
            degree[u]--;
            degree[v]++;
            if(mark)
                add(u,v,1);
        }
        int ok=1;
        int temp=0;
        for(int i=1;i<=26;i++)
        {
            if(used[i]&&fa[i]==i)
            {
                temp++;
            }
        }
        if(temp!=1)ok=0;//判断图是否联通
        temp=0;
        int v1=-1,v2=-1;
        for(int i=1;i<=26;i++)
        {
            if(degree[i]%2==1)//找出度数为奇数的点并记录下来
            {
                temp++;
                v1=i;
            }
            if(degree[i]%2==-1)
            {
                temp++;
                v2=i;
            }
        }
        if(temp==0||(temp==2&&v1!=-1&&v2!=-1))
        {
            if(temp==2)
            {
                add(v1,v2,1);//如果有两个点的度数为奇数且这两个点一个入度大于出度,一个出度大于入度,则将这两个点连上
                degree[v1]--;
                degree[v2]++;
            }
        }
        else ok=0;
        printf("Case %d: ",times);
        temp=0;
        if(!ok)printf("Poor boy!\n");
        else
        {
            for(int i=1;i<=26;i++)
            {
                if(degree[i]>0)
                    add(i,t,degree[i]/2);
                else if(degree[i]<0)
                {
                    add(s,i,-degree[i]/2);
                    temp+=-degree[i]/2;
                }
            }
            if(dinic(s,t)==temp)printf("Well done!\n");//如果跑出来的最大流正好能使得与s点相连的边都满流,则表示符合要求
            else printf("Poor boy!\n");
        }
    }
    return 0;
}
时间: 2024-10-10 05:27:03

hdu 3472 混合图的欧拉路径的相关文章

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

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发出的边全部满流,证明存在欧拉回路

hdu 3472 HS BDC 混合欧拉 网络流

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

POJ 1637 混合图的欧拉回路判定

题意:一张混合图,判断是否存在欧拉回路. 分析参考: 混合图(既有有向边又有无向边的图)中欧拉环.欧拉路径的判定需要借助网络流! (1)欧拉环的判定:一开始当然是判断原图的基图是否连通,若不连通则一定不存在欧拉环或欧拉路径(不考虑度数为0的点). 其实,难点在于图中的无向边,需要对所有的无向边定向(指定一个方向,使之变为有向边),使整个图变成一个有向欧拉图(或有向半欧拉图).若存在一个定向满足此条件,则原图是欧拉图(或半欧拉图)否则不是.关键就是如何定向? 首先给原图中的每条无向边随便指定一个方

UVa 10735 (混合图的欧拉回路) Euler Circuit

题意: 给出一个图,有的边是有向边,有的是无向边.试找出一条欧拉回路. 分析: 按照往常的思维,遇到混合图,我们一般会把无向边拆成两条方向相反的有向边. 但是在这里却行不通了,因为拆成两条有向边的话,就表示这个边能“在两个相反方向各经过一次”. 而题意是这个边只能经过一次. 假设图中存在欧拉回路,则所有点的出度out(i) 等于 入度in(i) 不妨这样,先将所有的无向边任意定向,对于out(u) > in(u)的点,可以将已经定向的无向边u->v反向为v->u,这样out(u) - i

POJ1637:Sightseeing tour(混合图的欧拉回路)

Sightseeing tour Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 10581   Accepted: 4466 题目链接:http://poj.org/problem?id=1637 Description: The city executive board in Lund wants to construct a sightseeing tour by bus in Lund, so that touri

POJ1637-Sightseeing tour/HDU-3472-HS BDC-最大流Dinic+判断混合图的欧拉图

前置知识: 混合图:一幅图中既有单向边,又有双向边. 混合图(既有有向边又有无向边的图)中欧拉环.欧拉路径的判定需要用到网络流这个算法!!! 有向图的欧拉回路的条件:所有的节点出度等于入度. 下面这两题基本差不多,但是建边啊.判断欧拉图啊等还是有区别的. 总之最后都是需要判断是否为满流,如果为满流则说明是欧拉回路. 注意: 1.tot初始化为-1,因为在进行反向边的时候通过异或是01.23.45....这样为一组的. if(di>0) { e[i].flow-=di; e[i^1].flow+=

混合图的欧拉回路判定

对于有向图和无向图的欧拉回路判定,很容易做到.那对于混合图呢?? 混合图就是图中既存在无向边又存在有向边的图. 至于解法: 转载自这里 把该图的无向边随便定向,计算每个点的入度和出度.如果有某个点出入度之差为奇数,那么肯定不存在欧拉回路.因为欧拉回路要求每点入度 = 出度,也就是总度数为偶数,存在奇数度点必不能有欧拉回路. 好了,现在每个点入度和出度之差均为偶数.那么将这个偶数除以2,得x.也就是说,对于每一个点,只要将x条边改变方向(入>出就是变入,出>入就是变出),就能保证出 = 入.如果

图论——欧拉通路、欧拉回路(有向图无向图混合图)

之前稍微了解有向图.无向图.混合图的欧拉通路.欧拉回路,这里做下笔记,以便日后翻阅. 无向图: 存在欧拉回路的条件:原图连通,每个结点均为偶度结点. 存在欧拉通路的条件:存在欧拉回路,或原图连通,有两个结点为奇度结点,其他结点均为偶度结点. 有向图: 存在欧拉回路的条件:基图连通,每个结点的入度等于出度. 存在欧拉通路的条件:存在欧拉回路,或基图连通,有一个结点入度等于出度+1,有一个结点出度等于入度+1,其他结点的入度等于出度. 混合图: 存在欧拉回路的条件: 1.将无向边随便定向,每个结点的