【日记】7.3

  今天的考试完全考水了,也不知道原因,各种题目看不清楚。莫名其妙的把所有的分都丢了、

第一题

基因重组 

【问题描述】 

工程师Enigma在研究项目遇到一个有关基因重组方面的难题。
众所周知,一个基因可以被认为是一个序列,包括4个核苷酸,可以由4个字母简单标记:A,C,G,T。
Enigma已经得到了一个基因,标记为"ATCC",诸如此类,他想将此基因重新组合产生一个新的,比如“CTCA”,他可以进行的有两种操作:
(1)将前两个字母交换,或者
(2)将第一个字母移到最后。
举例说明,可以使用第2种操作将“ATCC”变成“TCCA”,又可以使用第1种操作将“TCCA”变为“CTCA”。
你的任务是编程帮助Enigma找到完成一个基因重组所需的最少操作次数。 【输入格式】 第一行有一个整数N,表示基因序列的长度(
1<=N<=12),第二行有一个字符串,表示该基因序列,第三行是另一个字符串,即Enigma希望得到的基因序列。 对于每一个字母,它在两个字符串中出现的次数相同。 【输出格式】 一行,即最小操作次数。 【样例】 gene.in 4 ATCC CTCA gene.out 2


很明显的搜索,只有4^12种情况,但是由于空间给的小,只能用哈希来优化宽搜,至今还有两个点没过。

genea
  1 /**
  2 *Prob    : genea
  3 *Data    : 2012-7-3
  4 *Sol    : Search + hash
  5 */
  6 
  7 #include <cstdio>
  8 #include <queue>
  9 #include <string>
 10 #include <iostream>
 11 #include <cstring>
 12 
 13 #define MaxS 16777216
 14 
 15 using namespace std;
 16 
 17 struct node {
 18     int k,s;
 19 };
 20 queue <node> list;
 21 
 22 int n; 
 23 bool v[MaxS];
 24 char tma[20],tmb[20];
 25 int a[20],b[20],tm1[20],tm2[20],tmp[20];
 26 
 27 void Change_init()
 28 {
 29     int tmp = 1; a[n] = b[n] = 0;
 30     for (int i=n-1; i>=0; i--) {
 31         a[n] += a[i]*tmp;
 32         b[n] += b[i]*tmp;
 33         tmp *= 4;
 34     }
 35 }
 36 void Change(int *a)
 37 {
 38     int tmp = 1; a[n] = 0;
 39     for (int i=n-1; i>=0; i--) {
 40         a[n] += a[i]*tmp;
 41         tmp *= 4;
 42     }
 43 }
 44 void Change1(int *tm1)
 45 {
 46     int tmp = tm1[0];
 47     tm1[0] = tm1[1]; tm1[1] = tmp;
 48 }
 49 void Change2(int *tm2)
 50 {
 51     int tmp = tm2[0];
 52     for (int i=0; i<n-1; i++)
 53         tm2[i] = tm2[i+1];
 54     tm2[n-1] = tmp;
 55 }
 56 void Change3(int s,int *tmp)
 57 {
 58     int num = n;
 59     memset(tmp,0,sizeof(tmp));
 60     tmp[n] = s;
 61     while (s) {
 62         num--;
 63         tmp[num] = s%4;
 64         s /= 4;
 65     }
 66 }
 67 
 68 int Search()
 69 {
 70     memset(v,false,sizeof(v));
 71     node now,nowtm1,nowtm2;
 72     now.k = 0; now.s = a[n];
 73     list.push(now);
 74     v[a[n]] = true;
 75 
 76     while (!list.empty()) {
 77         now = list.front();
 78         list.pop();
 79         if (now.s == b[n])
 80             return now.k;
 81         Change3(now.s,tmp);
 82         for (int i=0; i<=n; i++)
 83             tm2[i] = tm1[i] = tmp[i];
 84         Change1(tm1); Change(tm1);
 85         Change2(tm2); Change(tm2);
 86         if (!v[tm1[n]]) {
 87             v[tm1[n]] = true;
 88             nowtm1.k = now.k+1;
 89             nowtm1.s = tm1[n];
 90             list.push(nowtm1);
 91         }
 92         if (!v[tm2[n]]) {
 93             v[tm2[n]] = true;
 94             nowtm2.k = now.k+1;
 95             nowtm2.s = tm2[n];
 96             list.push(nowtm2);
 97         }
 98     }
 99     
100 }
101 
102 int main()
103 {
104     freopen("genea.in","r",stdin);
105     freopen("genea.out","w",stdout);
106     
107     scanf("%d\n",&n);
108     scanf("%s\n",tma);
109     scanf("%s\n",tmb);
110     for (int i=0; i<n; i++) {
111         if (tma[i]=='A') a[i] = 0; 
112         if (tma[i]=='C') a[i] = 1; 
113         if (tma[i]=='G') a[i] = 2; 
114         if (tma[i]=='T') a[i] = 3; 
115 
116         if (tmb[i]=='A') b[i] = 0; 
117         if (tmb[i]=='C') b[i] = 1; 
118         if (tmb[i]=='G') b[i] = 2; 
119         if (tmb[i]=='T') b[i] = 3; 
120     }
121     Change_init();
122     
123     int ans;
124     if (a[n]==b[n]) ans = 0;
125     else ans=Search();
126     
127     printf("%d\n",ans);
128     
129     fclose(stdin); fclose(stdout);
130     return 0;
131 }


第二题

旅行 

【问题描述】 

一天,TZD想从0号村庄游历到n-1号村庄,这n个村庄由m条有向路连接,某两个村庄间可能有多条路相连。
当他在处于同一个强连通分支中的两个村庄间游历时,他可以租辆自行车来骑着,否则的话,就只能步行了。
说的再详细点,对于从村庄a到村庄b的每一条路,如果这两个村庄处在同一个强连通分支中,(这意味着你可以从a到达b,也可以从b到达a)
那么你可以租一辆自行车来骑行,所用时间为time[a][b]分钟,否则你必须步行通过,所用时间为2
*time[a][b]分钟。 TZD想尽快到达目的地,他希望在此过程中步行的路不超过k条。现在你需要为他计算出:在满足步行的路不超过k条的情况下,到达目的地所用的最短时间。 【输入格式】 输入文件包含若干组测试数据。 每一组数据的第一行有三个整数:n,m,k,含义如上所述(1<=n<=100,0<=m<=100,000,0<=k<=10)。 接下来有m行,每行有3个整数a,b,time[a][b],表示从村庄a至村庄b有一条路,骑自行车需time[a][b]分钟,而步行则需2*time[a][b]分钟。
0<=a,b<=n-1,0<time[a][b]<=10,000) 输入文件以单独的一行3个0表示结束。 【输出格式】 对于每一组测试数据,在一行输出其答案,如果TZD无法在步行不超过k条路的情况下到达目的地,则输出-1。 【样例】 travel.in 5 6 3 0 1 1 0 2 2 2 1 1 1 3 3 3 1 3 3 4 2 0 0 0 travel.out 9

很明显的可以用Floyd求连通图,然后用dis[i][k]来表示从0到点i,走了k次,所用的最短时间,用spfa求得最短路,然后在松弛操作的时候判断是否是强连通分量,从而可以看是用来更新dis[j][k+1]还是dis[j][k],其他的就是最简单的spfa了,也可以拆点来做

这道题悲剧的看错数据了,应该是多组数据,但是我是按一组写的,所以一分都没拿到,但是加上循环后就好了……

travel
  1 /**
  2 *Prob    : travela
  3 *Data    : 2012-7-3
  4 *Sol    : Floyd+spfa
  5 */
  6 
  7 #include <cstdio>
  8 #include <cstring>
  9 #include <algorithm>
 10 
 11 #define MaxN 120
 12 #define MaxK 20
 13 #define MaxList 1200000
 14 #define oo 1000000000
 15 
 16 using namespace std;
 17 
 18 struct node {
 19     int n,k;
 20 } list[MaxList];
 21 
 22 int n,k;
 23 int a[MaxN][MaxN];
 24 int dis[MaxN][MaxK];
 25 bool map[MaxN][MaxN];
 26 
 27 void Floyd()
 28 {
 29     for (int k=0; k<n; k++)
 30      for (int i=0; i<n; i++)
 31       for (int j=0; j<n; j++)
 32       {
 33         if (k==i||k==j||i==j) continue;
 34         if (map[i][k]&&map[k][j])
 35             map[i][j] = map[i][j] || true;
 36       }
 37 }
 38 
 39 void Spfa()
 40 {
 41     bool v[MaxN][MaxK];
 42     memset(v,false,sizeof(v));
 43     v[0][0] = true; 
 44     list[1].n = list[1].k = 0;
 45     int open = 1,closd = 0;
 46     for (int i=0; i<n; i++)
 47      for (int j=0; j<=k; j++)
 48         dis[i][j] = oo;
 49     dis[0][0] = 0;
 50     
 51     while (closd<open) {
 52         int nown = list[++closd].n;
 53         int nowk = list[closd].k;
 54         v[nown][nowk] = false;
 55         for (int tn=0; tn<n; tn++) {
 56             //????
 57             if (map[nown][tn]&&map[tn][nown]) {
 58                 //?б?
 59                 if (a[nown][tn])
 60                     if (dis[nown][nowk]+a[nown][tn]<dis[tn][nowk]) {
 61                         dis[tn][nowk] = dis[nown][nowk]+a[nown][tn];
 62                         if (!v[tn][nowk]) {
 63                             v[tn][nowk] = true;
 64                             list[++open].n = tn;
 65                             list[open].k = nowk;
 66                         }
 67                     }
 68             }
 69             //??????
 70             if (map[nown][tn]&&(!map[tn][nown])) {
 71                 if (nowk == k) break;
 72                 //?б?
 73                 if (a[nown][tn])
 74                     if (dis[nown][nowk]+2*a[nown][tn]<dis[tn][nowk+1]) {
 75                         dis[tn][nowk+1] = dis[nown][nowk]+2*a[nown][tn];
 76                         if (!v[tn][nowk+1]) {
 77                             v[tn][nowk+1] = true;
 78                             list[++open].n = tn;
 79                             list[open].k = nowk+1;
 80                         }
 81                     }
 82             }
 83         }
 84         
 85     }
 86 }
 87 
 88 int main()
 89 {
 90     freopen("travela.in","r",stdin);
 91     freopen("travela.out","w",stdout);
 92     
 93     int m,x,y,z;
 94     
 95 
 96     scanf("%d%d%d",&n,&m,&k);
 97     
 98     while (!(n==0&&m==0&&k==0)) {
 99     
100     memset(map,false,sizeof(map));
101     for (int i=0; i<n; i++)
102      for (int j=0; j<n; j++)
103         a[i][j] = oo;
104     for (int i=1; i<=m; i++) {
105         scanf("%d%d%d",&x,&y,&z);
106         a[x][y] = min(z,a[x][y]);
107         map[x][y] = true;
108     }
109     
110     Floyd();
111     
112     Spfa();
113     
114     int ans = oo;
115     for (int i=0; i<=k; i++)
116         ans = min(ans,dis[n-1][i]);
117     
118     if (ans==oo) ans = -1;
119     
120     printf("%d\n",ans);
121     
122     scanf("%d%d%d",&n,&m,&k);
123     }
124     
125     fclose(stdin); fclose(stdout);
126     return 0;
127 }

 

第三题

DNA重组 



 

【问题描述】 

有一次,Z国的研究人员从一些原始的有机组织中提取出了一条DNA链,他们的任务是通过对旧的DNA进行重组,进而生成一条新的DNA链。
他们投资了一个计划,用如下的方式使用基因剪和基因胶。 首先,他们将DNA链在某些连接点处断开,这样整个链就会就变成一些DNA片断,然后他们再决定是保留还是丢弃这些片断,如果保留这些片断,他们将利用基因胶把它们粘成一条新链。
注意,粘的过程中不能打乱这些片断原来的顺序。
在整个过程中他们不得不非常小心地确定这些片断的去留。 当然了,做这些操作是需要花费代价的,每一个“剪开”的操作代价为1,每一个“粘合”操作花费代价也为1。
请你写一个程序计算:如果存在一种方式生成一个新的DNA链,那么所需操作的最小代价是多少? 请看下面的例子: 旧的DNA:A
---T---A---C---C---G 剪开后: A T A---C C---G 保留: T C---G 新的DNA链: T---C---G 花费代价:4 【输入格式】 输入文件第一行有一个正整数T,表示接下来测试数据的个数。
每一个测试数据包含两行,每行一个字符串,第一个字符串表示旧的DNA链,第二行为新的DNA链。每个字符串都由
"A","T","C""G"组成,每一个字符串的长度均不超过3000。 【输出格式】 对于每一个测试数据,输出其最小花费,如果没办法生成新的DNA链,则输出“-1”。 【样例】 dna.in 2 ATACCG TCG ATACCG CTG dna.out 4 -1


动态规划,O(n^3)的算法好写,就是按照类似于最长公共子序列的方法,不过可以用两个数组来动归优化,很好写,但是不太好想,具体的就是

f[i][j][0]原始串的前i个和目标串的前j个匹配了,a[i]==b[j]

f[i][j][1]原始串的前i个和目标串的前j个匹配了,a[i]!=b[j] (即结尾是多余的)

最终的答案就是min(f[n][m][0],f[n][m][1]+1)

状态转移方程看代码

dna
 1 /**
 2 *Prob    : dna
 3 *Data    : 2012-7-3
 4 *Sol    : dp
 5 */
 6 
 7 #include <cstdio>
 8 #include <string>
 9 #include <cstring>
10 #include <iostream>
11 #include <algorithm>
12 
13 #define MaxN 3010
14 #define oo 100000000
15 
16 using namespace std;
17 
18 int T;
19 string a,b;
20 int f[MaxN][MaxN][2];
21 
22 void dp()
23 {    
24     memset(f,127,sizeof(f));
25     
26     for (int i=0; i<a.length(); i++)
27      for (int j=0; j<=i; j++)
28      {
29         if (i>0) f[i][j][1] = min(f[i-1][j][0],f[i-1][j][1]);
30         
31         if (a[i]!=b[j]) {
32             f[i][j][0] = oo; continue; }
33         if (a[i]==b[j]&&i==j&&j==0) {
34             f[i][j][0] = 0; continue; }
35         if (a[i]==b[j]&&i>0&&j==0) {
36             f[i][j][0] = 1; continue; }
37         if (j>0&&i>0)
38             f[i][j][0] = min(f[i-1][j-1][0],f[i-1][j-1][1]+3);
39      }
40 }
41 
42 int main()
43 {
44     freopen("dna.in","r",stdin);
45     freopen("dna.out","w",stdout);
46     
47     scanf("%d",&T);
48     int ans;
49     for (int i=1; i<=T; i++) {
50         cin>>a; cin>>b;
51         dp();
52         ans = min(f[a.length()-1][b.length()-1][0],f[a.length()-1][b.length()-1][1]+1);
53         if (ans>=oo) ans = -1;
54         printf("%d\n",ans);
55     }
56     
57     
58     fclose(stdin); fclose(stdout);
59     return 0;
60 }

 

 

下次调整心态,争取考好。

posted @ 2012-07-03 22:05  守護N1身边  阅读(264)  评论(0编辑  收藏  举报