(intermediate) DFS的应用 UVA 12273 Palindromic DNA

来源:互联网 发布:json 判断key是否存在 编辑:程序博客网 时间:2024/04/28 20:20

A DNA sequence is composed of a series of four possible nucleobases, namely Adenine, Guanine, Thymine and Cytosine; we will refer to each of these bases by their initial. For our purposes, nucleobases have an associated cyclic ``order'':A is followed by G, which in turn is followed by T, which is followed byC, which is followed by A again. State-of-the-art research in genomics has revealed the startling fact that many diseases are caused by certain subsequences of bases not forming a palindromic sequence! Your mission as a leading researcher at ICPC laboratories is to take a DNA string S and a series of subsetsP1,..., Pt of indices to characters (nucleobases) inS, and transform S so that each of the restrictions of the resulting string toP1,..., Pt are palindromic. (The restriction ofS to a subset P = {i1,i2,..., ik} of indices, where 0$ \le$i1 <i2 <...< ik < | S|, is the stringSi1Si2...Sik). It is possible to inspect any base ofS at will, but only three transformations can be applied to a base:

  1. Leave it unaltered.
  2. Increase it by 1 in the cyclic order of nucleobases (e.g. turnC into A).
  3. Decrease it by 1 (e.g. turn T into G).
Moreover, owing to limitations of current technology, it is impossible to modify two bases in consecutive positions of the sequence. Is our goal achievable?

By way of example, consider DNA sequence AGTAT. Number positions starting from0, and suppose we have the three subsets P1 = {1, 4}, P2 = {0, 1} andP3 = {0, 2, 4}. One solution is to increase the first character and decrease the last, yieldingS' = GGTAG. The restrictions of S' to P1, P2 and P3 areGG, GG and GTG, respectively; all of them are palindromic.

One case where no solution is possible is when the string is CATGC, and we require the subsequences determined by positions{0, 3} and {3, 4} be palindromic. Here, characters3, 0 and 4 would all need to become aT. But this entails modifying consecutive characters 3 and 4, which is not allowed.

Input 

The first line of each test case has two integers N andT ( 1$ \le$N$ \le$10 000, 1$ \le$T$ \le$6 000), the sequence length and number of subsets to consider. The next line contains the DNA sequence of lengthN, all of whose characters are in ACGT. The subsets are described by the followingT lines. Each line starts by ``L:'', whereL (0$ \le$L$ \le$N) is the number of positions in the subset, and is followed by L distinct integers between 0 and N - 1 in increasing order. Subsets may overlap partially or totally.

A blank line separates different test cases. The input file is terminated by a line containing `0 0'.

Output 

In a single line per test case, print `YES' if the task is solvable and `NO' otherwise.

Sample Input 

5 3AGTAT2: 1 42: 0 13: 0 2 45 3CATGC0:2: 0 32: 3 40 0

Sample Output 

YESNO




题意:给出一个DNA的序列,让后给出一些回文的集合,问你通过对DNA序列进行一定的改变,问能不能满足这些所有回文集合。当然改变时有要求的,相邻的两个不能同时改变,对于每一个字母,你可以+1、-1、+0,其中AGTC相当于对应是(0,1,2,3) 


思路:首先根据回文的集合,我们能够得出这个DNA序列那些地方的字母应该是相等的,根据这个我们能把所有的字母分类,一种是不需要改变的,这些可以忽略,另外的就是按照那些必须要相同的分类。然后我们得到了图的点:这些不同的组。然后对于每一组有四种可能性,AGTC,那么分裂出四个点,分别代表选取的状态为AGTC,然后我们分别验证是否可以取,如果取了这个字母,把所有的相邻位置都看看是否会影响到别的组不能选什么字母,如果a组选了字母x,使得b组不能选字母y,那么我们就用一条有向边从a组字母x的顶点指向b组字母y的定点。这里面我们的有向边只取定点标号小的指向定点标号大的。因为我们后面dfs搜索的时候可以一组一组按顺序的搜索。不需要打乱顺序。其实我觉得我的办法可能还是有问题,我觉得会有数据使得我的代码超时的,但非常神奇的过了。。。。我说说我搜的办法是我们用一个vis数组表示这个顶点是否可取,如果是0,表示可以取,如果<0,表示不能取,那么再用一个sum数组表示每一组剩下的可取的状态,如果在搜索的过程中,发现后面有一个组的sum值已经为0了,那么就不必搜下去了,显然不会有解的。在搜的时候,如果我们为某一组选定了一个状态,就把这一组能指向 的组的vis减1,如果vis减为了-1,就把对应的sum也减一。直到每一组都分配了方案,就结束了。


代码:

#include<iostream>#include<algorithm>#include<cstdio>#include<string.h>#include<stack>#include<cstring>#include<vector>using namespace std;#define mp make_pairconst int maxn = 10000 + 5;vector<int> G[maxn*4];int sum[maxn];vector<int> block[maxn];int bkno[maxn];int bk_cnt;int S[maxn],P[maxn];char DNA[maxn];int n, m;void input(){scanf("%s", DNA);for (int i = 0; i < n; ++i){G[i].clear();if (DNA[i] == 'A') S[i] = 0;else if (DNA[i] == 'G') S[i] = 1;else if (DNA[i] == 'T') S[i] = 2;else if (DNA[i] == 'C') S[i] = 3;//printf("%d ", S[i]);}//cout << endl;for (int i = 0; i < m; ++i){int k; scanf("%d:", &k);for (int j = 0; j < k; ++j) scanf("%d", P + j);for (int j = 0; j < k / 2; ++j) {//printf("%d %d\n", P[j], P[k - 1 - j]);G[P[j]].push_back(P[k - 1 - j]);G[P[k - 1 - j]].push_back(P[j]);}}}int vis[maxn*4];void dfs(int x){if (vis[x]) return;vis[x] = 1;bkno[x] = bk_cnt;block[bk_cnt].push_back(x);for (int i = 0; i < G[x].size(); ++i){int y = G[x][i];dfs(y);}}void findblock(){memset(vis, 0, sizeof(vis));memset(bkno, -1, sizeof(bkno));bk_cnt = 0;for (int i = 0; i < n; ++i) if (!vis[i] && G[i].size()){block[bk_cnt].clear();dfs(i);sort(block[bk_cnt].begin(), block[bk_cnt].end());++bk_cnt;}}bool Ok(int s){int val = s % 4, bk = s / 4;//printf("%d %d\n", val,bk);stack<int> v;for (int i = 0; i < block[bk].size(); ++i){int x = block[bk][i];//printf("%d\n", x);if (S[x] != val && (S[x] + 1) % 4 != val && (S[x] + 3) % 4 != val) return false;if (S[x] == val) continue;int y = x + 1;//printf("%d %d\n", x, y);//printf("%d %d\n", bkno[x], bkno[y]);if (bkno[x] == bkno[y]){if (S[x] != val&&S[y] != val) return false;}else if (bkno[y] != -1 && bkno[y]>bkno[x]){for (int j = 0; j < 4; ++j) if (j != S[y]){v.push(bkno[y] * 4 + j);}}y = x - 1;if (y < 0 || bkno[x] >= bkno[y] || bkno[y]==-1) continue;for (int j = 0; j < 4; ++j) if (j != S[y]){v.push(bkno[y] * 4 + j);}}while (v.size()){G[s].push_back(v.top());v.pop();}return true;}bool dfs1(int x){if (x>=n) return true;for (int j = 0; j < 4; ++j) if (vis[x*4+j]>=0){bool flag = true;for (int k = 0; k < G[x * 4 + j].size(); ++k){int y = G[x * 4 + j][k];--vis[y];if (vis[y] == -1) --sum[y / 4];if (sum[y / 4] == 0) flag = false;}--vis[x*4+j];if (flag && dfs1(x + 1)) return true;++vis[x * 4 + j];for (int k = 0; k < G[x * 4 + j].size(); ++k){int y = G[x * 4 + j][k];++vis[y];if (vis[y] == 0) ++sum[y / 4];}}return false;}void solve(){memset(vis, -1, sizeof(vis));memset(sum, 0, sizeof(sum));//printf("%d\n", bk_cnt);for (int i = 0; i <= bk_cnt; ++i) sum[i] = 4;for (int i = 0; i < 4 * bk_cnt; ++i){G[i].clear();if (Ok(i)) vis[i] = 0;else sum[i / 4]--;}n = bk_cnt;//for (int i = 0; i < n; ++i)//{//printf("%d ", sum[i]);//}//cout << endl;if (dfs1(0)) printf("YES\n");else printf("NO\n");}int main(){while (scanf("%d%d", &n, &m) && n + m){input();findblock();solve();}}


0 0
原创粉丝点击