變形課杭電1181——深搜,廣搜,並查集

Problem Description

呃……變形課上Harry碰到了一點小麻煩,因爲他並不像Hermione那樣能夠記住所有的咒語而隨意的將一個棒球變成刺蝟什麼的,但是他發現了變形咒語的一個統一規律:如果咒語是以a開頭b結尾的一個單詞,那麼它的作用就恰好是使A物體變成B物體.
Harry已經將他所會的所有咒語都列成了一個表,他想讓你幫忙計算一下他是否能完成老師的作業,將一個B(ball)變成一個M(Mouse),你知道,如果他自己不能完成的話,他就只好向Hermione請教,並且被迫聽一大堆好好學習的道理.

Input
測試數據有多組。每組有多行,每行一個單詞,僅包括小寫字母,是Harry所會的所有咒語.數字0表示一組輸入結束.

Output
如果Harry可以完成他的作業,就輸出”Yes.”,否則就輸出”No.”(不要忽略了句號)

Sample Input

so
soon
river
goes
them
got
moon
begin
big
0

Sample Output
Yes.

我想大家題意都看懂了吧,就是輸入一個單詞比如sfaffac則表示s可以變成c,則給出一連串的單詞,就有好多種變換的形式,則題目要求給粗的這些變換是否能吧b變換成m………

很明顯這是一道搜索題,但是後來一想,由於這道題的有點特別,有連續對應性,所以用並查集也是可以的
接下來我就把三種方法全都講一下:

1.廣搜(0ms)

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
#define N 1000
bool vis[N];//標記是否走過
char str[N][N];
bool flag;//標記
void bfs(int n)
{
    queue<int> q;     //定義一個普通隊列
    int a,len,i;
    for(i=0;i<n;i++)  //先把所有的b開頭的全部先放入隊列裏
    {
        if(str[i][0]=='b')
        {
            vis[i]=true;  //標記走過
            q.push(i);
        }
    }
    while(!q.empty())
    {
        a=q.front();
        q.pop();
        len=strlen(str[a])-1;
        if(str[a][len]=='m')    //如果找到m停止循環
        {
            flag=true;
            return;
        }
        for(i=0;i<n;i++)
        {
            if(vis[i])//走過的跳過
                continue;
            if(str[i][0]==str[a][len])//如果與上一個末字母相對就放入隊列
            {
                vis[i]=true;
                q.push(i);
            }
        }
    }
}
int main()
{
    int i,j,m;
    i=0;
    while(~scanf("%s",&str[i]))
    {
        vis[i]=false;
        i++;
        if(str[i-1][0]=='0')      //遇到0輸入終止標記就進行廣度搜索
        {
            vis[i]=false;
            flag=false;
            bfs(i);
            if(flag)
                printf("Yes.\n");
            else
                printf("No.\n");
            i=0;
        }
    }
    return 0;
}

2.深搜(46ms)

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<string.h>
#include<queue>
using namespace std;
#define N 10010
int vis[N];//深搜的時候一定要標記是否搜過,不然會Runtime Error(STACK_OVERFLOW)
char str[N][N];
bool flag;
int k;
void dfs(char n)
{
    int i,j,l;
    for(i=0;i<k;i++)
    {
        l=strlen(str[i])-1;
        if(str[i][0]==n&&vis[i]==0)
        {
            if(n=='m')     //搜索到m終點返回
            {
                flag=true;
                return ;
            }
            vis[i]=1;//標記走過
            dfs(str[i][l]); //向下一層搜索
            vis[i]=0;//消除標記
        }
    }
    return ;
}
int main()
{
    int i,j,m;
    k=0;
    while(~scanf("%s",&str[k]))
    {
        memset(vis,0,sizeof(vis));
        vis[k]=false;
        k++;
        if(str[k-1][0]=='0')
        {
            vis[k]=false;
            flag=false;
            dfs('b');       //以b爲頭開始搜
            if(flag)
                printf("Yes.\n");
            else
                printf("No.\n");
            k=0;
        }
    }
    return 0;
}

3.並查集(15ms)

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
using namespace std;
#define N 10000
int pre[N];
int find(int x)   //着共同的最終boss
{
    int r=x;
    while(pre[r]!=r)
        r=pre[r];
    return r;
}
int main()
{
    int n,i,j,a,b,mark1,mark2,l;
    char word[1000];
    while(~scanf("%s",&word))
    {
        if(word[0]=='0')
            continue;
        mark1=mark2=0;
        memset(pre,0,sizeof(pre));
        for(i=1;i<=N;i++)
            pre[i]=i;
        l=strlen(word);/*
        a=word[0]-'a'+1;b=word[l-1]-'a'+1;
        if(word[0]=='b')
            mark1=1;
        if(word[l-1]=='m')
            mark2=1;
        pre[find(a)]=pre[find(b)];對第一組數據處理,其實這一段可以沒有的,後來做搜索的時候發現可以簡化*/
        while(~scanf("%s",&word))//並查集處理,如果處理後存在b和m位置指向的最終boss是同一個boss,則最起碼證明了b和m是有聯通的路徑的,只不過還要證明方向問題!!!!!
                {
            if(word[0]=='0')
                break;
            l=strlen(word);
            a=word[0]-'a'+1;b=word[l-1]-'a'+1;
            if(word[0]=='b')//證明方向,如果存在命令裏有存在首字母是b末字母是m的情況,則定存在一條的由b指向m的路徑。
                mark1=1;
            if(word[l-1]=='m')
                mark2=1;
            pre[find(a)]=pre[find(b)];
        }
        if(pre[2]==pre[13]&&mark1==1&&mark2==1)
            printf("Yes.\n");
        else
            printf("No.\n");
    }
    return 0;
}    


發佈了48 篇原創文章 · 獲贊 90 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章