您的位置:首页 > 其它

codeforces 889B. Restoration of string(拓扑排序)

2017-11-18 12:54 411 查看
给出十万个字符串,总长度不超过十万,要求构造一个字符串,使得所有给出的字符串在这个串当中都是出现次数最多子串。输出长度最短的答案。如果有多个答案,输出字典序最小的。

思路:

  把每个给出的字符串中,相邻的两个字符连上一条有向边。

  首先我们要知道,如果有解,那么这个解应该是若干条链贪心加和。所以出现环则无解。

  其次每个点的出入度最大只能为1,否则无法满足题意。

  最后要注意处理单个字符的情况。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 5;

char str[maxn];
int vis[maxn], out[maxn], in[maxn], input[maxn];
vector<string>vec;
vector<int>G[maxn];
string temp;
int ok;
void dfs(int cur)
{
if(ok == 0) return ;
vis[cur] = 1;
temp += 'a' + cur;
for(auto v : G[cur])
{
if(vis[v])  ok = 0;
dfs(v);
}
}

bool solve()
{
for(int i = 0; i < 26; i++)
{
out[i] += G[i].size();
for(auto o : G[i])  in[o]++;
}

for(int i = 0; i < 26; i++)
{
if(in[i] > 1 || out[i] > 1) return false;
}

for(int i = 0; i < 26; i++)
{
ok = 1;
temp = "";
if(in[i] == 0 && out[i])    dfs(i);
vec.push_back(temp);
if(ok == 0) return false;
}

for(int i = 0; i < 26; i++)
{
if(vis[i] == 0 && in[i])    return false;

if(vis[i] == 0 && input[i])
{
string t = "";
t += ('a' + i);
vec.push_back(t);
}
}
sort(vec.begin(), vec.end());

string ans = "";
for(auto o : vec)   ans += o;
cout << ans << endl;
return true;
}
int main()
{
int n;
scanf("%d", &n);
for(int i = 0; i < n; i++)
{
scanf("%s", str);
int len = strlen(str);
if(len == 1)    input[str[0] - 'a'] = 1;
else
{
for(int j = 0; j < len - 1; j++)
{
int lb = str[j] - 'a', rb = str[j + 1] - 'a';
G[lb].push_back(rb);
}
}
}
for(int i = 0; i < 26; i++)
{
sort(G[i].begin(), G[i].end());
G[i].resize(unique(G[i].begin(), G[i].end()) - G[i].begin());
}

if(solve() == 0)    puts("NO");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: