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

46 篇文章 0 订阅

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

Recommend
zhengfeng   |   We have carefully selected several similar problems for you:   3475  3474  3473  3471  3470 
 


题意:给出n个单词,问这些单词能否首尾相连组成一个整体,其中部分单词可以翻转。

思路:将每个单词的首尾字母看成结点,每个单词看成一条边,可以看出这是一张混合图,要求判断是否有欧拉路。使用判断欧来回路的方法,如果存在欧拉回路那么就一定存在欧拉路了;否则如果有且仅有两个点的(出度-入度)是奇数,那么给这两个点加边,判断是否存在欧拉回路。注意这一题要判断图的连通性。

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <string>
#include <map>
#include <stack>
#include <vector>
#include <set>
#include <queue>
#pragma comment (linker,"/STACK:102400000,102400000")
#define maxn 30
#define MAXN 2005
#define mod 1000000009
#define INF 0x3f3f3f3f
#define pi acos(-1.0)
#define eps 1e-6
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define FRE(i,a,b)  for(i = a; i <= b; i++)
#define FREE(i,a,b) for(i = a; i >= b; i--)
#define FRL(i,a,b)  for(i = a; i < b; i++)
#define FRLL(i,a,b) for(i = a; i > b; i--)
#define mem(t, v)   memset ((t) , v, sizeof(t))
#define sf(n)       scanf("%d", &n)
#define sff(a,b)    scanf("%d %d", &a, &b)
#define sfff(a,b,c) scanf("%d %d %d", &a, &b, &c)
#define pf          printf
#define DBG         pf("Hi\n")
const int MAXM = 30000;
typedef long long ll;
using namespace std;

struct Edge
{
    int to,next,cap,flow;
}edge[MAXM];

int st,ed;
int d[MAXN];
int tol,m,s;
int head[MAXN];
int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN];
int in[MAXN],out[MAXN];

void init()
{
    tol=0;
    memset(head,-1,sizeof(head));
    memset(in,0,sizeof(in));
    memset(out,0,sizeof(out));
}

//加边,单向图三个参数,双向图四个参数
void addedge(int u,int v,int w,int rw=0)
{
    edge[tol].to=v; edge[tol].cap=w; edge[tol].next=head[u];
    edge[tol].flow=0; head[u]=tol++;
    edge[tol].to=u; edge[tol].cap=rw; edge[tol].next=head[v];
    edge[tol].flow=0; head[v]=tol++;
}

//输入参数:起点,终点,点的总数
//点的编号没有影响,只要输入点的总数
int sap(int start,int end,int N)
{
    memset(gap,0,sizeof(gap));
    memset(dep,0,sizeof(dep));
    memcpy(cur,head,sizeof(head));
    int u=start;
    pre[u]=-1;
    gap[0]=N;
    int ans=0;
    while (dep[start]<N)
    {
        if (u==end)
        {
            int Min=INF;
            for (int i=pre[u];i!=-1;i=pre[edge[i^1].to])
                if (Min>edge[i].cap-edge[i].flow)
                    Min=edge[i].cap-edge[i].flow;
            for (int i=pre[u];i!=-1;i=pre[edge[i^1].to])
            {
                edge[i].flow+=Min;
                edge[i^1].flow-=Min;
            }
            u=start;
            ans+=Min;
            continue;
        }
        bool flag=false;
        int v;
        for (int i=cur[u];i!=-1;i=edge[i].next)
        {
            v=edge[i].to;
            if (edge[i].cap-edge[i].flow && dep[v]+1==dep[u])
            {
                flag=true;
                cur[u]=pre[v]=i;
                break;
            }
        }
        if (flag)
        {
            u=v;
            continue;
        }
        int Min=N;
        for (int i=head[u];i!=-1;i=edge[i].next)
            if (edge[i].cap-edge[i].flow && dep[edge[i].to]<Min)
            {
                Min=dep[edge[i].to];
                cur[u]=i;
            }
        gap[dep[u]]--;
        if (!gap[dep[u]]) return ans;
        dep[u]=Min+1;
        gap[dep[u]]++;
        if (u!=start) u=edge[pre[u]^1].to;
    }
    return ans;
}

int father[MAXN];

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

void Union(int a,int b)
{
    int fa=find_father(a);
    int fb=find_father(b);
    if (fa!=fb)
        father[fa]=fb;
}

int main()
{
//    freopen("C:/Users/asus1/Desktop/IN.txt","r",stdin);
    int i,j,t,n,d,cas=1,x;
    char str[30];
    scanf("%d",&t);
    while (t--)
    {
        init();
        for (i=0;i<30;i++)
            father[i]=i;
        scanf("%d",&n);
        for (i=0;i<n;i++)
        {
            scanf("%s %d",str,&d);
            int len=strlen(str);
            out[str[0]-'a']++;
            in[str[len-1]-'a']++;
            x=str[0]-'a';
            if (d==1)
                addedge(str[0]-'a',str[len-1]-'a',1);
            Union(str[0]-'a',str[len-1]-'a');
        }
        int cnt=0;
        int w[30];
        bool flag=true;
        for (i=0;i<26;i++)
        {
            if (in[i]||out[i])
            {
                if (find_father(i)!=find_father(x))
                {
                    flag=false;
                    break;
                }
                if ((out[i]-in[i])%2)
                    w[cnt++]=i;
            }
        }
        if (cnt!=0&&cnt!=2||!flag)
        {
            printf("Case %d: Poor boy!\n",cas++);
            continue;
        }
        if (cnt==2)
        {
            in[w[0]]++;
            out[w[1]]++;
            addedge(w[0],w[1],1);
        }
        sap(26,27,28);
        for (i=head[26];i+1;i=edge[i].next)
        {
            if (edge[i].cap>0&&edge[i].cap>edge[i].flow)
            {
                flag=false;
                break;
            }
        }
        if (flag) printf("Case %d: Well done!\n",cas++);
        else printf("Case %d: Poor boy!\n",cas++);
    }
    return 0;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值