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.
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.
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.
5 aca aba aba cab bac
YES abacaba
4 abc bCb cb1 b13
NO
7 aaa aaa aaa aaa aaa aaa aaa
YES aaaaaaaaa
题意:
有一个串的长度为n+2
现在给出这个串的n个子串,每个子串由3个字符组成。
字符可以是大小写字母和数字。
求原串。
分析:
将一个子串看成一条边,前2个字符看成节点1,后2个字符看成节点2。
节点1到节点2连边构造图,求欧拉通路。
统计每个节点的入度和出度。
判断是否存在欧拉通路的条件是:
1、原有向图忽略方向后联通(可dfs也可并查集,我用的是并查集)
2、abs(in[i]-out[i])==1的点 有0个或者2个
这里两点之间可能有重边,图中也可能有自环。
而且点有20万个。
我用vis[a][b]记录ab之间的边应该走的次数,dfs找路径时搜到一次减1,减到0就不能再走了
开始跑到第30组数据就TLE过不了了
卡住的数据是20万个zzz
然后我特判了一个字符的情况1000+ms才过- -
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
using namespace std;
typedef long long ll;
char s[5];
int in[4100],out[4100];
vector<int> g[4100];
int fa[4100],pp;
char ans[200010];
int vis[4100][4100];
bool have[4100];
int sb[4100];
int change(char x)
{
int ret;
if(x>='a' && x<='z')
ret = x-'a';
else if(x>='A' && x<='Z')
ret = x-'A'+26;
else ret = x-'0'+52;
return ret;
}
char cha(int x)
{
char ret;
if(x>=0 && x<=25)
ret = x+'a';
else if(x>=26 && x<=51)
ret = x-26+'A';
else ret = x-52+'0';
return ret;
}
void dfs(int st)
{
for(int i=0;i<g[st].size();i++)
{
int r = g[st][i];
if(!vis[st][r]) continue;
vis[st][r]--;
dfs(r);
}
int b;
b = st%62;
ans[pp++] = cha(b);
}
void init()
{
for(int i=0;i<4000;i++)
g[i].clear();
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
memset(vis,0,sizeof(vis));
memset(ans,0,sizeof(ans));
memset(have,0,sizeof(have));
for(int i=0;i<4005;i++) fa[i] = i;
pp = 0;
}
int find(int x)
{
// if(x == fa[x]) return x;
// int t = find(fa[x]);
// fa[x] = t;
// return t;
return fa[x]==x?x:(fa[x]=find(fa[x]));
}
void join(int x,int y)
{
int fx = find(x);
int fy = find(y);
if(fx!=fy) fa[fx] = fy;
}
int main()
{
int n,a,b,c,x,y;
while(~scanf("%d",&n))
{
init();
for(int i=0;i<n;i++)
{
scanf("%s",s);
a = change(s[0]);
b = change(s[1]);
c = change(s[2]);
x = a*62+b;
y = b*62+c;
vis[x][y]++;
g[x].push_back(y);
out[x]++;
in[y]++;
join(x,y);
have[x] = true;
have[y] = true;
}
int flag = 0,father = -1;
int cnt = 0,pi; //特判一个字符的部分
for(int i=0;i<4005;i++){ //
if(have[i]){ //
cnt++; //
pi = i; //
} //
} //
if(cnt==1){
puts("YES");
for(int i=1;i<=n+2;i++)
printf("%c",cha(pi%62));
printf("\n");
continue;
}
for(int i=0;i<4005;i++)
{
if(!have[i]) continue;
if(father==-1){
father = find(i);
}
else
{
if(find(i)!=father)
{
flag = 1;
break;
}
}
}
if(flag)
{
puts("NO");
continue;
}
int cnt1 = 0,st = -1;
for(int t=0;t<4005;t++)
{
if(abs(in[t]-out[t]) >1)
{
flag = 1;
break;
}
if(abs(in[t]-out[t]) == 1)
{
if(out[t]-in[t]==1) st = t;
cnt1++;
}
}
if(flag || !(cnt1==0 || cnt1==2))
{
puts("NO");
continue;
}
int sss,w;
if(st!=-1) sss = st;
else sss = father;
dfs(sss);
w = (sss-sss%62)/62;
ans[pp++] = cha(w);
if(pp!=n+2) puts("NO");
else{
puts("YES");
for(int i=pp-1;i>=0;i--)
printf("%c",ans[i]);
printf("\n");
}
}
return 0;
}
看了别人的代码 129ms就过了- -
存边是将 边计数和终点一起存到队列
然后搜的时候只记录边的序号。
代码来源:http://blog.youkuaiyun.com/sdj222555/article/details/43245421
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <algorithm>
#include <map>
#include <ctime>
#define MAXN 111111
#define MAXM 1122222
#define INF 1000000007
#define eps 1e-8
using namespace std;
int n;
typedef pair<int, int> PII;
vector<PII> g[66 * 66];
int num[66 * 66];
int in[66 * 66], out[66 * 66];
int fa[66 * 66], v[66 * 66];
int en[66 * 66][66 * 66];
int vis[222222], nv[222222];
int st[222222];
char s[211111][6];
int find(int x) {
if(x == fa[x]) return x;
int t = find(fa[x]);
fa[x] = t;
return t;
}
void join(int x, int y) {
int fx = find(x);
int fy = find(y);
if(fx != fy) fa[fx] = fy;
}
int getc(char c) {
if(c >= 'a' && c <= 'z') return c - 'a';
if(c >= 'A' && c <= 'Z') return c - 'A' + 26;
return c - '0' + 52;
}
int ind;
void dfs(int u, int eid) {
for(int i = 0; i < g[u].size(); i++) {
int tid = g[u][i].second;
if(vis[tid]) {
vis[tid] --;
dfs(g[u][i].first, tid);
}
}
if(eid) st[ind++] = eid;
}
int main()
{
scanf("%d", &n);
for(int i = 0; i < 66 * 66; i++) fa[i] = i;
for(int i = 1; i <= n; i++) {
scanf("%s", s[i]);
int a = getc(s[i][0]);
int b = getc(s[i][1]);
int c = getc(s[i][2]);
int id1 = a * 62 + b;
int id2 = b * 62 + c;
v[id1] = 1; v[id2] = 1;
join(id1, id2);
if(en[id1][id2] == 0) en[id1][id2] = i, g[id1].push_back(PII(id2, i));
in[id2]++;
out[id1]++;
vis[en[id1][id2]]++;
}
int tmp = -1, flag = 0;
for(int i = 0; i < 66 * 66; i++) {
if(!v[i]) continue;
if(tmp == -1) tmp = find(i);
else {
if(tmp != find(i)) {
flag = 1;
break;
}
}
}
int cnt = 0, src = -1;
for(int i = 0; i < 66 * 66; i++) {
if(!v[i]) continue;
if(abs(in[i] - out[i]) >= 2) {
flag = 1;
break;
} else if(abs(in[i] - out[i]) == 1) {
cnt ++;
if(out[i] - in[i] == 1) src = i;
}
}
if(src == -1) src = tmp;
if(flag) {
printf("NO\n");
} else if(cnt == 0 || cnt == 2) {
dfs(src, 0);
printf("YES\n");
for(int i = ind - 1; i >= 0; i--) {
int tid = st[i];
if(i == ind - 1) printf("%s", s[tid]);
else printf("%c", s[tid][2]);
}
printf("\n");
} else {
printf("NO\n");
}
return 0;
}