508D Tanya and Password (map+dfs)

D. Tanya and Password
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

While dad was at work, a little girl Tanya decided to play with dad's password to his secret database. Dad's password is a string consisting of n + 2 characters. She has written all the possible n three-letter continuous substrings of the password on pieces of paper, one for each piece of paper, and threw the password out. Each three-letter substring was written the number of times it occurred in the password. Thus, Tanya ended up with n pieces of paper.

Then Tanya realized that dad will be upset to learn about her game and decided to restore the password or at least any string corresponding to the final set of three-letter strings. You have to help her in this difficult task. We know that dad's password consisted of lowercase and uppercase letters of the Latin alphabet and digits. Uppercase and lowercase letters of the Latin alphabet are considered distinct.

Input

The first line contains integer n (1 ≤ n ≤ 2·105), the number of three-letter substrings Tanya got.

Next n lines contain three letters each, forming the substring of dad's password. Each character in the input is a lowercase or uppercase Latin letter or a digit.

Output

If Tanya made a mistake somewhere during the game and the strings that correspond to the given set of substrings don't exist, print "NO".

If it is possible to restore the string that corresponds to given set of substrings, print "YES", and then print any suitable password option.

Sample test(s)
input
5
aca
aba
aba
cab
bac
output
YES
abacaba
input
4
abc
bCb
cb1
b13
output
NO
input
7
aaa
aaa
aaa
aaa
aaa
aaa
aaa
output
YES
aaaaaaaaa

题意:给你原本字符串S的子串段,子串段性质:长度3,与S相反,全都有,所以有n-2个,无序的,问你你能找出原串S。

思路:其实可以把每个子串段分为2部分,前2个和后两个,根据常识一进一出的规则,当然会出现相同的子串段,那就找in,out的差,找到起点然后dfs出原串S反转就得到结果了。

在实现中可以用map来一一对应,也可以用自己处理下字符串的值来特殊表示,一些特殊情况也要考虑,代码中给出了,写完后我发现在一个情况下超时了,这里就引入了go数组,比如200000  zzz zzz zzz zzz......  这里每个g[u][i]的边太多了,如果还从头开始遍历就果断超时了。

代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 200005;
int in[N],out[N],vis[N],go[N];
map<string,int> ma;
map<int,string> mb;
vector<pair<int,int> > g[N];
int tot = 0,flag = 0;
string ans;
int add(string s)
{
    if(ma.find(s) == ma.end())
    {
        ma[s] = tot;
        mb[tot] = s;
        tot++;
    }
    return ma[s];
}
void dfs(int u)
{
    for(; go[u]<g[u].size(); go[u]++)//本来使用i=0写的...果断超时了。
    {
        if(!vis[g[u][go[u]].second])
        {
            vis[g[u][go[u]].second] = 1;
            dfs(g[u][go[u]].first);
        }
    }
    if(!flag)
    {
        flag = 1;
        ans += mb[u][1];
    }
    ans += mb[u][0];
}
int main()
{
    //freopen("in.txt","r",stdin);
    int n;
    string str;
    cin >> n;
    for(int i=0; i<n; i++)
    {
        cin >> str;
        int u = add(str.substr(0,2));//起始位置0,长度2的子串
        int v = add(str.substr(1,2));
        in[v]++;
        out[u]++;
        g[u].push_back(make_pair(v,i));
    }
    ans = "";//多组的话要清空字符串
    int start = 0,cnt = 0;
    for(int i=0; i<tot; i++)
    {
        if(out[i]>in[i])
        {
            cnt += out[i] - in[i];
            if(cnt > 1)
            {
                puts("NO");
                return 0;
            }
            start = i;
        }
    }
    dfs(start);
    if(ans.length() == n + 2)//这里是防止输入的数据里有多组循环子串如:4 aba bab cdc dcd
    {
        puts("YES");
        reverse(ans.begin(),ans.end());
        cout << ans << endl;
    }
    else
        puts("NO");
    return 0;
}
View Code

 

posted @ 2015-03-17 13:02  Doli  阅读(133)  评论(0编辑  收藏  举报