【DFS】codeforces 638 B. Making Genome in Berland

题目传送门

Berland scientists face a very important task - given the parts of short DNA fragments, restore the dinosaur DNA! The genome of a berland dinosaur has noting in common with the genome that we’ve used to: it can have 26 distinct nucleotide types, a nucleotide of each type can occur at most once. If we assign distinct English letters to all nucleotides, then the genome of a Berland dinosaur will represent a non-empty string consisting of small English letters, such that each letter occurs in it at most once.

Scientists have n genome fragments that are represented as substrings (non-empty sequences of consecutive nucleotides) of the sought genome.
You face the following problem: help scientists restore the dinosaur genome. It is guaranteed that the input is not contradictory and at least one suitable line always exists. When the scientists found out that you are a strong programmer, they asked you in addition to choose the one with the minimum length. If there are multiple such strings, choose any string.

Description

给出 n 个子串,每个子串中的每个字符都不同(只包含26个小写字母),找到最短的原串,要求原串中的字符也都不同,保证答案一定存在。

Solution

可以确定的是,每个字母后边要么有唯一确定的字母,要么没有字母。
那么只要 某个子串的第一个字符 不是 其他子串的第一个字符 ,那么这个字符就可以作为一个无前驱的结点。
所以只需要记录每个字符后边紧跟着的字符,然后直接 dfs 去找即可。

Code

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
using namespace std;
typedef long long LL;
const int MaxN = 3e5 + 5;

int vis[50];
vector<int> G[50];

void dfs(int x) {
	vis[x] = 2; // 表示字符x已经用过
	cout << (char)('a' + x);
	for(int i = 0; i < G[x].size(); i++) {
		int u = G[x][i];
		if(vis[u] != 2) {
			dfs(u);
		}
	}
}

int main()
{
	int n; cin >> n;
	for(int i = 1; i <= n; i++) {
		string s; cin >> s;
		for(int j = 1; j < s.size(); j++) {
			vis[s[j]-'a'] = 1;
			G[s[j-1]-'a'].push_back(s[j] - 'a'); //如果这个字符在 子串的非第一个字符的位置上 出现过就打上标记,说明不是要寻找的无前驱结点
		}
		if(!vis[s[0]-'a']) vis[s[0]-'a'] = 6; //用来寻找无前驱结点
	}
	for(int i = 0; i < 26; i++) {
		if(vis[i] == 6) dfs(i); //如果当前结点没有前驱
	}
	cout << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值