A Za, A Za, Fighting...

坚信:勤能补拙

问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=2192

思路:
原本以为是类似于PKU 1936的简单题,结果Sample测试不过,发现对于像cat, tree这样包含相同字母(这里是t)的例子需要回溯,于是DFS,这样结果虽然正确了,但是却TLE...
准确的做法是动态规划,艾,今天三题没有一个是自己想出来的...悲剧...
详细的状态转化方程见代码注释

代码:
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #define MAX_LEN 201
 5 char first[MAX_LEN+1], second[MAX_LEN+1];
 6 char final[MAX_LEN*2];
 7 int flen, slen, tlen;
 8 int table[MAX_LEN][MAX_LEN];
 9 
10 /* 
11  * f[i][j] represent whether final[1..i+j] could be formed from first[1..i] and second[1..j]
12  * f[i][j] is true if:
13  *         a. final[i+j]==first[i] && f[i-1][j] is true, or
14  *         b. final[i+j]==second[j] && f[i][j-1] is true
15  */
16 int 
17 dp()
18 {
19     int i, j, mark;
20     mark = 1;
21     for(i=1; i<=flen; i++) {
22         if(first[i]==final[i] && mark)
23             table[i][0= 1;
24         else {
25             table[i][0= 0;
26             mark = 0;
27         }
28     }
29     mark = 1;
30     for(j=1; j<=slen; j++) {
31         if(second[j]==final[j] && mark)
32             table[0][j] = 1;
33         else {
34             table[0][j] = 0;
35             mark = 0;
36         }
37     }
38     for(i=1; i<=flen; i++) {
39         for(j=1; j<=slen; j++) {
40             if((final[i+j]==first[i]&&table[i-1][j]) || (final[i+j]==second[j]&&table[i][j-1]))
41                 table[i][j] = 1;
42             else
43                 table[i][j] = 0;
44         }
45     }
46     return table[flen][slen];
47 }
48 
49 int
50 main(int argc, char **argv)
51 {
52     int tests, cnt=0;
53     scanf("%d"&tests);
54     while(tests--) {
55         scanf("%s %s %s", first+1, second+1, final+1);
56         flen = strlen(first+1);
57         slen = strlen(second+1);
58         tlen = strlen(final+1);
59         printf("Data set %d: %s\n"++cnt, dp()?"yes":"no");
60     }
61 }
posted @ 2010-08-13 22:33 simplyzhao 阅读(189) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1080

思路:
想法与最长公共子序列类似
用f[i][j]表示str_a[1..i]与str_b[1..j]的相似度,而所求即f[len_a][len_b],需要注意初始化部分的代码
状态转移方程见代码注释

代码:
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #define MAX_LEN 101
 5 #define INF 'I'
 6 #define Score(ch_a, ch_b) (score[map[ch_a-'A']][map[ch_b-'A']])
 7 int len_a, len_b;
 8 char str_a[MAX_LEN+1], str_b[MAX_LEN+1];
 9 int table[MAX_LEN][MAX_LEN];
10 const int score[][5= {{5,-1,-2,-1,-3}, {-1,5,-3,-2,-4}, {-2,-3,5,-2,-2}, {-1,-2,-2,5,-1}, {-3,-4,-2,-1,-65535}};
11                               /* A    C          G    I                               T */  
12 const int map[] = {0,-1,1,-1,-1,-1,2,-1,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,3};
13 
14 /*
15  * f[i][j] represent the similarity of str_a[1..i] and str_b[1..j], so:
16  *    f[i][j] = max { f[i-1][j-1]+Score(str_a[i], str_b[j]), 
17  *                    f[i-1][j] + Score(str_a[i], '-'),
18  *                    f[i][j-1] + Score('-', str_b[j]) }
19  */
20 int
21 dp()
22 {
23     int i, j, a, b, c, max;
24     /* Attention: Initialization */
25     table[0][0= 0;
26     for(i=1; i<=len_a; i++)
27         table[i][0= table[i-1][0+ Score(str_a[i], INF);
28     for(j=1; j<=len_b; j++)
29         table[0][j] = table[0][j-1+ Score(str_b[j], INF);
30     
31     for(i=1; i<=len_a; i++) {
32         for(j=1; j<=len_b; j++) {
33             a = table[i-1][j-1+ Score(str_a[i], str_b[j]);
34             b = table[i-1][j] + Score(str_a[i], INF);
35             c = table[i][j-1+ Score(INF, str_b[j]);
36             max = a > b ? a : b;
37             max = c > max ? c : max;
38             table[i][j] = max;
39         }
40     }
41     return table[len_a][len_b];
42 }
43 
44 int
45 main(int argc, char **argv)
46 {
47     int tests;
48     scanf("%d"&tests);
49     while(tests--) {
50         scanf("%d %s"&len_a, str_a+1);
51         scanf("%d %s"&len_b, str_b+1);
52         printf("%d\n", dp());
53     }
54 }
posted @ 2010-08-13 14:07 simplyzhao 阅读(106) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1160

思路:
事先知道这是动态规划的题,于是就拼命往这方面想,想啊想啊想啊想,终于灵感一现:
      可以用f[i][j]表示到第i个村镇为止,建造j个邮局所需要的最小距离
心中窃喜,感觉应该挺靠谱,于是继续深入,直觉告诉我f[i][j]与f[i-1][j], f[i-1][j-1]应该有关系,貌似成了第i个村镇建不建邮局的子问题,继续苦思冥想,结果却还是想不出来。

无奈,还是看别人的思路吧:
      用f[i][j]表示前i个邮局建在前j个村镇所需要的最小距离(貌似,跟我之前想的刚好相反)
      f[i][j] = min( f[i-1][k] + cost[k+1][j],  i-1<=k<=j-1),cost[i][j]表示在村镇i与j之间建造一个post office的最小距离(人家说显然在中点)

艾,差之毫厘,谬以千里,如何有效地表示和分析最优子结构是关键:一个问题的解,如何通过其子问题来表示和求解

代码:
 1 /* 752K 79MS */
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #define MAX_V 301
 6 #define MAX_P 31
 7 #define INF 0x7FFFFFFF
 8 int v, p;
 9 int pos[MAX_V];
10 int cost[MAX_V][MAX_V];
11 int table[MAX_P][MAX_V];
12 
13 void
14 init()
15 {
16     int i, j, k, mid, diff;
17     for(i=1; i<=v; i++) {
18         for(j=i; j<=v; j++) {
19             diff = 0;
20             mid = (i+j)/2;
21             for(k=i; k<=j; k++)
22                 diff += ((pos[k]>pos[mid])?(pos[k]-pos[mid]):(pos[mid]-pos[k]));
23             cost[i][j] = cost[j][i] = diff;
24         }
25     }
26 }
27 
28 int
29 dp()
30 {
31     int i, j, k, min, tmp;
32     memset(table, 0sizeof(table));
33     for(j=1; j<=v; j++)
34         table[1][j] = cost[1][j];
35     for(i=2; i<=p; i++) {
36         for(j=i+1; j<=v; j++) {
37             min = INF;
38             for(k=i-1; k<=j-1; k++) {
39                 tmp = table[i-1][k] + cost[k+1][j];
40                 min = tmp<min ? tmp : min;
41             }
42             table[i][j] = min;
43         }
44     }
45     return table[p][v];
46 }
47 
48 int
49 main(int argc, char **argv)
50 {
51     int i;
52     while(scanf("%d %d"&v, &p)!=EOF) {
53         for(i=1; i<=v; i++)
54             scanf("%d", pos+i);
55         init();
56         printf("%d\n", dp());
57     }
58 }


posted @ 2010-08-13 12:45 simplyzhao 阅读(177) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1159

思路:
看完题目,完全不知道该怎么做
参考discuss,发现原来DP这么这么地强大,自己那是相当菜
设ch[1]..ch[n]表示字符串1至n位,i为左游标,j为右游标 ,则i从n递减,j从i开始递增。
min[i][j]表示i和j之间至少需要插入多少个字符才能对称,初始置全0 ,我们最终需要得到的值是min[1][n].
则
if(ch[i]==ch[j])                                    //如果两个游标所指字符相同,向中间缩小范围
    min[i][j]=min[i+1][j-1];
else
    min[i][j] = 1 +(min[i+1][j]和min[i][j-1]中的较小值);     //如果不同,典型的状态转换方程
额,状态方程看明白了,结果发现代码居然不知道怎么写...那个汗哪...
原因是没有发现当i>j时,min[i][j] = 0

代码(记忆化搜索):
 1 /* Time: 1594MS */
 2 #include<stdio.h>
 3 #include<stdlib.h>
 4 #include<string.h>
 5 #define MAX_LEN 5001
 6 char str[MAX_LEN+1];
 7 int len;
 8 short memory[MAX_LEN][MAX_LEN];
 9 
10 /*
11  * f[i][j] represent the minimal insert for str[i..j]
12  *
13  * f[i][j] = f[i+1][j-1], if str[i]==str[j], otherwise
14  * f[i][j] = min(f[i+1][j], f[i][j-1]) + 1
15  */
16 int
17 func(int i, int j)
18 {
19     int a, b;
20     if(i >= j)
21         return 0;
22     if(memory[i][j])
23         return memory[i][j];
24     if(str[i] == str[j])
25         memory[i][j] = func(i+1, j-1);
26     else {
27         a = func(i+1, j);
28         b = func(i, j-1);
29         memory[i][j] = a<? a+1 : b+1;
30     }
31     return memory[i][j];
32 }
33 
34 int
35 main(int argc, char **argv)
36 {
37     while(scanf("%d"&len) != EOF) {
38         memset(memory, 0sizeof(memory));
39         scanf("%s", str+1);
40         printf("%d\n", func(1, len));
41     }
42 }

代码(dp):
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #define MAX_LEN 5001
 5 char str[MAX_LEN];
 6 int len;
 7 short table[MAX_LEN][MAX_LEN];
 8 
 9 short
10 dp()
11 {
12     int i, j;
13     /* if i>j, then table[i][j] = 0 */
14     for(i=len-1; i>=1; i--) {
15         for(j=i; j<=len; j++) {
16             if(str[i] == str[j])
17                 table[i][j] = table[i+1][j-1];
18             else
19                 table[i][j] = table[i+1][j]<table[i][j-1? table[i+1][j]+1 : table[i][j-1]+1;
20         }
21     }
22     return table[1][len];
23 }
24 
25 int
26 main(int argc, char **argv)
27 {
28     while(scanf("%d"&len) != EOF) {
29         memset(table, 0sizeof(table));
30         scanf("%s", str+1);
31         printf("%d\n", dp());
32     }
33 }
posted @ 2010-08-12 19:47 simplyzhao 阅读(141) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=2250

思路:
以单词为单位的LCS,另外需要记录路径信息

代码:
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #define MAX_NUM 101
 5 #define MAX_LEN 31
 6 char first[MAX_NUM][MAX_LEN];
 7 char second[MAX_NUM][MAX_LEN];
 8 int fcnt, scnt;
 9 int table[MAX_NUM][MAX_NUM];
10 char path[MAX_NUM][MAX_NUM];
11 
12 void
13 output(int i, int j)
14 {
15     if(i==0 || j==0)
16         return;
17     if(path[i][j] == 'u')
18         output(i-1, j);
19     else if(path[i][j] == 'l')
20         output(i, j-1);
21     else {
22         output(i-1, j-1);
23         printf("%s ", first[i-1]);
24     }
25 }
26 
27 void
28 lcs()
29 {
30     int i, j;
31     for(i=0; i<=fcnt; i++)
32         table[i][0= 0;
33     for(j=0; j<=scnt; j++)
34         table[0][j] = 0;
35     for(i=1; i<=fcnt; i++) {
36         for(j=1; j<=scnt; j++) {
37             if(strcmp(first[i-1], second[j-1]) == 0) {
38                 table[i][j] = table[i-1][j-1+ 1;
39                 path[i][j] = 'y';
40             } else if(table[i-1][j] > table[i][j-1]) {
41                 table[i][j] = table[i-1][j];
42                 path[i][j] = 'u';
43             } else {
44                 table[i][j] = table[i][j-1];
45                 path[i][j] = 'l';
46             }
47         }
48     }
49 }
50 
51 int
52 main(int argc, char **argv)
53 {
54     while(1) {
55         fcnt = scnt = 0;
56         memset(table, 0sizeof(table));
57         memset(path, 0sizeof(path));
58         if(scanf("%s", first[fcnt++]) == EOF)
59             break;
60         while(scanf("%s", first[fcnt]) && first[fcnt][0]!='#')
61             ++fcnt;
62         while(scanf("%s", second[scnt]) && second[scnt][0]!='#')
63             ++scnt;
64         lcs();
65         output(fcnt, scnt);
66         printf("\n");
67     }
68 }
posted @ 2010-08-12 15:32 simplyzhao 阅读(119) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1953

思路:
如果想通了,其实就是道挺简单的动规题
zero_end[i]记录第i位以0结尾的合法排列
one_end[i]记录第i位以1结尾的合法排列
状态方程即:
                 zero_end[i+1] = zero_end[i] + one_end[i]
                 one_end[i+1] = zero_end[i]
以深度搜索的递归树即可观察得出以上结论(*^__^*) 嘻嘻……

代码:
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #define MAX_LEN 45
 5 int zero_end[MAX_LEN+1];
 6 int one_end[MAX_LEN+1];
 7 
 8 int
 9 build_table()
10 {
11     int i;
12     zero_end[1= 1;
13     one_end[1= 1;
14     for(i=2; i<=45; i++) {
15         zero_end[i] = zero_end[i-1+ one_end[i-1];
16         one_end[i] = zero_end[i-1];
17     }
18 }
19 
20 int
21 main(int argc, char **argv)
22 {
23     int i, n, tests;
24     build_table();
25     scanf("%d"&tests);
26     for(i=1; i<=tests; i++) {
27         scanf("%d"&n);
28         printf("Scenario #%d:\n%d\n\n", i, zero_end[n]+one_end[n]);
29     }
30 }
posted @ 2010-08-12 12:57 simplyzhao 阅读(155) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1163

思路:
比较基础、容易的动态规划
table[i][j]记录从根节点到第i行第j个元素的最大和
状态转移方程:
             table[i][j] = max(table[i][j-1], table[i][j]) + num[i][j]

为了节省空间,对于三角形的保存,采用了一维数组

代码:
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #define MAX_N 101
 5 #define MAX_LEN 5051 /* 1+2+3++100 */
 6 int rows, num[MAX_LEN];
 7 int table[MAX_N][MAX_N];
 8 
 9 /* table[i][j] = max(table[i-1][j-1]+num[i][j], table[i-1][j]+num[i][j] */
10 int
11 dp()
12 {
13     int i, j, k, tmp, max, rt;
14     table[0][0= num[0];
15     for(i=1; i<rows; i++) {
16         tmp = i*(i+1)/2;
17         for(j=0; j<=i; j++) {
18             max = 0;
19             for(k=1; k>=0; k--
20                 if(j-k>=0 && j-k<=i-1/* parent index: [i-1][j-k] */
21                     max = table[i-1][j-k]+num[tmp+j]>max ? table[i-1][j-k]+num[tmp+j] : max;
22             table[i][j] = max;
23         }
24     }
25     rt = 0;
26     for(j=0; j<rows; j++)
27         if(table[rows-1][j] > rt)
28             rt = table[rows-1][j];
29     return rt;
30 }
31 
32 int
33 main(int argc, char **argv)
34 {
35     int i, j, tmp;
36     while(scanf("%d"&rows) != EOF) {
37         for(i=0; i<rows; i++) {
38             tmp = i*(i+1)/2;
39             for(j=0; j<=i; j++
40                 scanf("%d", num+(tmp+j));
41         }
42         memset(table, 0sizeof(table));
43         printf("%d\n", dp());
44     }
45 }
posted @ 2010-08-12 11:06 simplyzhao 阅读(99) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=1276

思路:
典型的多重背包问题,参考背包九讲,一次AC
深刻理解:01背包、完全背包、多重背包

代码:
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #define MAX_VOLUMN 100001
 5 #define MAX_N 11
 6 #define max(a,b) ((a)>(b) ? (a) : (b))
 7 int vol, n;
 8 int cv[MAX_N], num[MAX_N], f[MAX_VOLUMN];
 9 
10 /* f[i][v] = max(f[i-1][v], f[i-1][v-cost[i]]+value[i]) */
11 void
12 ZeroOnePack(int cost, int value)
13 {
14     int v;
15     for(v=vol; v>=cost; v--)
16         f[v] = max(f[v], f[v-cost]+value);
17 }
18 
19 /* f[i][v] = max(f[i-1][v], f[i][v-cost[i]]+value[i]) */
20 void
21 CompletePack(int cost, int value)
22 {
23     int v;
24     for(v=cost; v<=vol; v++)
25         f[v] = max(f[v], f[v-cost]+value);
26 }
27 
28 void
29 MultiplePack(int cost, int value, int amount)
30 {
31     int k = 1;
32     if(cost*amount >= vol)
33         CompletePack(cost, value);
34     else {
35         while((amount-k) >= 0) {  
36             ZeroOnePack(cost*k, value*k);
37             amount -= k;
38             k = k*2;
39         }
40         ZeroOnePack(cost*amount, value*amount);
41     }
42 }
43 
44 void
45 dp()
46 {
47     int i;
48     for(i=1; i<=n; i++)
49         MultiplePack(cv[i], cv[i], num[i]);
50 }
51 
52 int
53 main(int argc, char **argv)
54 {
55     int i;
56     while(scanf("%d %d"&vol, &n)!=EOF) {
57         memset(f, 0sizeof(f));
58         for(i=1; i<=n; i++)
59             scanf("%d %d", num+i, cv+i);
60         dp();
61         printf("%d\n", f[vol]);
62     }
63 }
posted @ 2010-08-11 22:03 simplyzhao 阅读(174) | 评论 (0)编辑 收藏
问题:
http://acm.pku.edu.cn/JudgeOnline/problem?id=3624

思路:
典型的01背包问题,动态规划,参考背包九讲
注意需要使用滚动数组,否则MLE

代码:
 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<string.h>
 4 #define MAX_N 3403
 5 #define MAX_M 12881
 6 #define max(a,b) ((a)>(b) ? (a) : (b))
 7 int n, m;
 8 /* MLE: int table[MAX_N][MAX_M]; */
 9 int table[MAX_M];
10 int weight[MAX_N], rate[MAX_N];
11 
12 void
13 dp()
14 {
15     int i, j;
16     memset(table, 0sizeof(table));
17     for(i=1; i<=n; i++)
18         for(j=m; j>=weight[i]; j--/* Attention: descent order */
19             table[j] = max(table[j], table[j-weight[i]]+rate[i]);
20 }
21 
22 int
23 main(int argc, char **argv)
24 {
25     int i;
26     while(scanf("%d %d"&n, &m)!=EOF) {
27         for(i=1; i<=n; i++)
28             scanf("%d %d", weight+i, rate+i);
29         dp();
30         printf("%d\n", table[m]);
31     }
32 }
posted @ 2010-08-11 10:57 simplyzhao 阅读(209) | 评论 (0)编辑 收藏
     摘要:                                                         ...  阅读全文
posted @ 2010-08-11 09:40 simplyzhao 阅读(200) | 评论 (0)编辑 收藏
仅列出标题
共21页: First 11 12 13 14 15 16 17 18 19 Last 

导航

<2024年12月>
24252627282930
1234567
891011121314
15161718192021
22232425262728
2930311234

统计

常用链接

留言簿(1)

随笔分类

随笔档案

搜索

最新评论

阅读排行榜

评论排行榜