• 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;
    }
  • 相关阅读:
    【转】Android系统中Fastboot和Recovery所扮演的角色。
    【转】Android ROM分析(1):刷机原理及方法
    【转】ANDROIDROM制作(一)——ROM结构介绍、精简和内置、一般刷机过程
    【转】使用fastboot命令刷机流程详解
    检测是否安装或者开启flash
    CentOS中/英文环境切换教程(CentOS6.8)
    id: cannot find name for user ID xxx处理办法
    linux重命名所有find查找到的文件/文件夹
    linux过滤旧文件中的空行和注释行剩余内容组成新文件
    CentOS和AIX查看系统序列号
  • 原文地址:https://www.cnblogs.com/chaoswr/p/8095161.html
Copyright © 2020-2023  润新知