POJ 1386&&HDU 1116 Play on Words(我以后再也不用cin啦!!!)

Play on Words

Some of the secret doors contain a very interesting word puzzle. The team of archaeologists has to solve it to open that doors. Because there is no other way to open the doors, the puzzle is very important for us. 
There is a large number of magnetic plates on every door. Every plate has one word written on it. The plates must be arranged into a sequence in such a way that every word begins with the same letter as the previous word ends. For example, the word ``acm'' can be followed by the word ``motorola''. Your task is to write a computer program that will read the list of words and determine whether it is possible to arrange all of the plates in a sequence (according to the given rule) and consequently to open the door. 

Input

The input consists of T test cases. The number of them (T) is given on the first line of the input file. Each test case begins with a line containing a single integer number Nthat indicates the number of plates (1 <= N <= 100000). Then exactly Nlines follow, each containing a single word. Each word contains at least two and at most 1000 lowercase characters, that means only letters 'a' through 'z' will appear in the word. The same word may appear several times in the list. 

Output

Your program has to determine whether it is possible to arrange all the plates in a sequence such that the first letter of each word is equal to the last letter of the previous word. All the plates from the list must be used, each exactly once. The words mentioned several times must be used that number of times.  If there exists such an ordering of plates, your program should print the sentence "Ordering is possible.". Otherwise, output the sentence "The door cannot be opened.". 

Sample Input

 

3
2
acm
ibm
3
acm
malform
mouse
2
ok
ok

Sample Output

The door cannot be opened.
Ordering is possible.
The door cannot be opened.

HDU timelimit 5000ms

POJ timelimit 1000ms   emmmmmm~ 

然后这题用cin巨坑啊!!!浪费了我两个小时...

首先很显然是一道求欧拉路的问题,开始我用邻接表+dfs在POJ上做的,交了一发TLE...emmmm。后面才发现总共就26个点,于是换邻接矩阵,又交一发,TLEx2...emmmmm。后思考许久,没想到怎么优化,然后搜到HDU也有一道相同的题,但limit5000ms,遂在HDU交一发..1150ms左右,这离1000ms很近啊?开始我还是有点怀疑cin是不是慢了,但想着怎么着也不会慢这么多吧?

遂在网上找了另一种做法并查集,hoho~这个看起来要快一些,生搬硬套一番别人的代码(我为了图方便还是用的cin输入),POJ上交一发...果不其然TLE,我(哔......)...

没办法,最后把string换成char数组,cin换成scanf,dfs交一发 320+ms,,,并查集交一发310+ms....我......我以后再也不用cin啦jojo!!

 

/**
*   time: 320ms
*   邻接矩阵dfs求欧拉路
*/
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#define MIN(x,y) ((x)>(y))?(y):(x)
#define MAX(x,y) ((x)>(y))?(x):(y)

using namespace std;

const int inf = 0x3f3f3f3f;
const double dinf = 0xffffffff;
const int vspot = 30;
const int espot = 100010;
const int qspot = 40050;


int indeg[vspot], outdeg[vspot];
int g[vspot][vspot];
int N, cnt, k;

void init()
{
    cnt = k = 0;
    memset( g, 0, sizeof(g) );
    memset( indeg, 0, sizeof(indeg) );
    memset( outdeg, 0, sizeof(outdeg) );
}

int read()
{
    scanf( "%d", &N );
    int x, y, start;
    char str[1010];
    for( int i = 0; i < N; i++ )
    {
        scanf( "%s", str );            //别用cin...
        int len = strlen(str);

        x = str[0] - 'a';
        y = str[len-1] - 'a';

        g[x][y]++;
        indeg[y]++;
        outdeg[x]++;
        start = MIN(x,y);            //初始搜索点须是出现过的点,不用MIN也行直接start=x
    }

    return start;
}

int dfs( int x )
{
    for( int i = 0; i < 26; i++ )
        if ( g[x][i] )
        {
            g[x][i]--;
            dfs(i);
            k++;
        }
    return k;
}

int main()
{
    int all;
    cin >> all;
    while( all-- )
    {
        init();
        int start = read();

        int test = 0, cne = 0, cns = 0;                //cns表示满足入度等于出度-1的点 个数
        for( int i = 0; i < 26; i++ )                //cne表示满足入度等于出度+1的点 个数
            if ( indeg[i] != outdeg[i] )
            {
                if ( indeg[i] == outdeg[i] + 1 )
                    cne++;
                else if ( indeg[i] == outdeg[i] - 1 )
                    { cns++; start = i; }
                else
                    test++;                            
            }

        if ( test )
            cout << "The door cannot be opened." << endl;
        else if ( !((cns==0&&cne==0) || (cns==1&&cne==1)) )
            cout << "The door cannot be opened." << endl;
        else
        {
            test = dfs(start);                        

            if ( test == N )
                cout << "Ordering is possible." << endl;
            else
                cout << "The door cannot be opened." << endl;   //若dfs搜不完全图说明不连通
        }
    }

    return 0;
}

 

/**
*    time: 320ms
*    并查集
*/
#include <iostream>
#include <cstdio>
#include <string.h>
#include <algorithm>
#define MIN(x,y) ((x)>(y))?(y):(x)
#define MAX(x,y) ((x)>(y))?(x):(y)

using namespace std;

const int inf = 0x3f3f3f3f;
const double dinf = 0xffffffff;
const int vspot = 30;
const int espot = 10010;
const int qspot = 40050;

int root[vspot], indeg[vspot], outdeg[vspot];
int N;
bool vis[vspot];


int find( int x )
{
    return x == root[x] ? x : root[x]=find(root[x]);    //路径压缩其实没必要..毕竟就26个点
}


void unions( int x, int y )
{
    int x1, x2;
    x1 = find(x);
    x2 = find(y);
    if(x1 != x2)
        root[x2] = x1;
}


void init()
{
    memset( indeg, 0, sizeof(indeg) );
    memset( outdeg, 0, sizeof(outdeg) );
    memset( vis, false, sizeof(vis) );
    for( int i = 0; i < vspot; i++ )
        root[i] = i;
}


int main()
{
    int all;
    cin >> all;
    while( all-- )
    {
        init();
        scanf( "%d", &N );
        char str[1500];
        int x, y;
        for( int i = 0; i < N; i++ )
        {
            scanf( "%s", str );
            int len = strlen(str);
            x = str[0] - 'a';
            y = str[len-1] - 'a';

            vis[x] = vis[y] = true;
            indeg[y]++;
            outdeg[x]++;
            unions(x,y);
        }


        int test = 0, cne = 0, cns = 0;                        
        for( int i = 0; i < 26; i++ )
            if ( indeg[i] != outdeg[i] )                    //测试方法和前面的代码一样
            {
                if ( indeg[i] == outdeg[i] + 1 )
                    cne++;
                else if ( indeg[i] == outdeg[i] - 1 )
                    cns++;
                else
                    test++;
            }

        if ( test )
            cout << "The door cannot be opened." << endl;
        else if ( !((cns==0&&cne==0) || (cns==1&&cne==1)) )
            cout << "The door cannot be opened." << endl;
        else
        {
            test = -1;
            int k = 0;
            for( int i = 0; i < 26; i++ )
                if ( vis[i] )
                    if ( root[i] == i )                //换成test!=root[i]就不对??why??
                        k++;
            if ( k == 1 )
                cout << "Ordering is possible." << endl;
            else
                cout << "The door cannot be opened." << endl;
        }
    }

    return 0;
}

 

转载于:https://www.cnblogs.com/chaoswr/p/8095161.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值