成长轨迹61 【ACM算法之路 百炼poj.grids.cn】【动态规划】【2806、1661、2757】
动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。
动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。
如果k个变量可以构成一个状态的话,并且这k个变量的取值范围分别为n1,n2...那么可以用一个k维数组来存储这些状态k[n1][n2]...
2806:公共子序列
1 #include <cstdio>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5
6 char s1[210];
7 char s2[210];
8 int len[210][210];
9 int main()
10 {
11 while(scanf("%s %s",s1+1,s2+1)>0)//【0位作为空标识,不使用0位】
12 //【while(scanf("%s %s",s1,s2)>0)和while(scanf("%s %s",s1,s2))不同!】
13 {
14 int len1=strlen(s1+1);//【0位作为空标识,不使用0位】
15 int len2=strlen(s2+1);
16 //其中一个字符串长度为0时,
17 //即以下两种情况时,最长公共子序列的长度均为0
18 for(int i=0;i<=len1;i++)//j==0
19 len[i][0]=0;
20 for(int j=0;j<=len2;j++)//i==0
21 len[0][j]=0;
22
23 for(int i=1;i<=len1;i++)
24 for(int j=1;j<=len2;j++)
25 {
26 if(s1[i]==s2[j])
27 len[i][j]=len[i-1][j-1]+1;
28 else
29 {
30 len[i][j]=len[i-1][j]>len[i][j-1]?len[i-1][j]:len[i][j-1];
31 }
32 }
33
34 printf("%d\n",len[len1][len2]);
35 }
36 return 0;
37 }
1661:帮助 Jimmy
1 #include <cstdio>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5
6 #define INF 1000000
7 int k,max,n;
8 int minleft[1010];
9 int minright[1010];
10
11 struct platform
12 {
13 int left;
14 int right;
15 int high;
16 }p[1010];
17
18 int cmp(const void * a,const void * b)
19 {
20 return ((struct platform *)b)->high - ((struct platform *)a)->high;
21 }
22 int min(int k,bool left)
23 {
24 int x;
25 if(left)
26 {
27 x=p[k].left;
28 }
29 else
30 {
31 x=p[k].right;
32 }
33 int y=p[k].high;
34
35 int i;
36 for(i=k+1;i<=n;i++)
37 {
38 if(p[i].left<=x&&p[i].right>=x)
39 break;
40 }
41 if(i==n+1)//下面没有板
42 {
43 if(y>max)
44 return INF;
45 else
46 return y;
47 }
48 else if(y-p[i].high>max)
49 return INF;
50
51 int lefttime=y-p[i].high+x-p[i].left;
52 int righttime=y-p[i].high+p[i].right-x;
53
54 if(minleft[i]==-1)//动态规划
55 minleft[i]=min(i,true);
56 if(minright[i]==-1)
57 minright[i]=min(i,false);
58
59 lefttime+=minleft[i];
60 righttime+=minright[i];
61
62 return lefttime<righttime?lefttime:righttime;
63
64 }
65 int main()
66 {
67 int t;
68 scanf("%d",&t);
69 for(int a=0;a<t;a++)
70 {
71 memset(minleft,-1,sizeof(minleft));
72 memset(minright,-1,sizeof(minright));
73 int x,y;
74 scanf("%d%d%d%d",&n,&x,&y,&max);
75 p[0].left=x;
76 p[0].right=x;
77 p[0].high=y;
78 for(int i=1;i<=n;i++)//【注意加上开头一共是n+1个!】
79 {
80 scanf("%d%d%d",&p[i].left,&p[i].right,&p[i].high);
81 }
82 qsort(p,n+1,sizeof(platform),cmp);//【一定要排序。。。而且一共是n+1个!】
83
84 printf("%d\n",min(0,true));
85
86 }
87
88 return 0;
89 }
2757:最长上升子序列
1 #include <cstdio>
2 int num[1010];
3 int max[1010];
4 int main()
5 {
6 int n;
7 scanf("%d",&n);
8 for(int i=0;i<n;i++)
9 {
10 scanf("%d",&num[i]);
11 }
12 max[0]=1;
13 for(int i=1;i<n;i++)
14 {
15 int temp=0;
16 for(int j=0;j<i;j++)
17 {
18 if(num[i]>num[j])
19 {
20 if(temp<max[j])
21 //这里是看看比num[i]小的num[j]中哪个上升子序列最长
22 temp=max[j];
23 }
24 }
25 max[i]=temp+1;//算上自己
26 }
27 int nmax=-1;
28 for(int i=0;i<n;i++)
29 if(nmax<max[i])
30 nmax=max[i];
31 printf("%d\n",nmax);
32 return 0;
33 }