首页 > 代码库 > DP的简单应用

DP的简单应用

Problem A:简单的图形覆盖

Time Limit:1000MS  Memory Limit:65536K
Total Submit:201 Accepted:104 

Description 

有一个2*n的方格,要用若干个1*2的模块覆盖,模块可以横放,也可以竖放.问对于给定的n(n<=100),有多少种不同的覆盖方法.

Input 

有多个测试用例,每个用例占一行,为一个正整数n

Output 

对于每个测试用例,输出一行相应的结果

Sample Input 

9

11

Sample Output 

55

144

分析:

f(n)={ 1  n=1

     2  n=2

   f(n-1)+f(n-2) n>2

}

 1 #include<stdio.h> 2 int A[101]; 3 int main() 4 { 5    int n,i; 6    while(scanf("%d",&n)!=EOF) 7    {  8        A[0]=1;A[1]=1; 9        if(n==1||n==0)  printf("%d\n",A[0]);10        else11        {12        for(i=2;i<n;i++)13            A[i]=A[i-1]+A[i-2]; 14        printf("%d\n",A[i]);15        }16    }17    return 0;18 }
View Code

 

递归解决

 1 #include <stdio.h> 2 #include <string.h> 3 int A[101]; 4 int f(int n) 5 { 6     memset(A,-1,sizeof(A)); 7     if (A[n]!=-1) return A[n]; 8     if(n==0||n==1)  9     {10         A[n]=1;11     }12     else13     {14         A[n]=f(n-1)+f(n-2);15         16     }17     return A[n];18 }19 int main()20 {21     int n;22     while(scanf("%d",&n)!=EOF)23    {       24        printf("%d\n",f(n));25    }26    return 0;27 }
View Code

 

Problem B:最大子段和

Time Limit:1000MS  Memory Limit:65536K
Total Submit:574 Accepted:299 

Description 

有一组数,-2 5 4 -3 7 的最大子段和是13, 是从57.

Input 

第一行输入一个n(1〈 N=100 ) 表示这一组数有多长,第二行是N个数
测试案例有多个,n=0时结束

Output 

输出这一组数的最大子段和.

Sample Input 

5

-2 5 4 -3 7

10

9 -3 8 -28 98 -30 -20 50 -24 10

0

Sample Output 

13

98

分析:

A  

-2

5

4

-3

7

表示A0~Ai数段中包含第i个元素的最大子段和

-2

5

9

6

13

 

B[i]={

  A[i]   i=0;

  max{ B[i-1]+A[i] , A[i] } i>0;

}

 1 #include<stdio.h> 2 int A[101]; 3 int B[101]; 4 int main() 5 { 6    int n,i,max; 7    scanf("%d",&n); 8    while(n!=0) 9    { 10        for(i=0;i<n;i++)11            scanf("%d",&A[i]);12        B[0]=A[0];13        for(i=0;i<n;i++)14            if(B[i-1]<0) B[i]=A[i];15            else16                B[i]=B[i-1]+A[i];17 /*       max=B[0];   18        for(i=1;i<n;i++) if(max<B[i]) max=B[i];19        printf("%d\n",max);20        scanf("%d",&n);*/21 printf("%d\n",B[n-1]);22 23    }24    return 0;25 }
View Code

 

Problem C:最长公共子序列

Time Limit:1000MS  Memory Limit:65536K
Total Submit:164 Accepted:99 

Description 

我们称序列Z=是序列X=的子序列当且仅当存在严格上升的序列,使得对j=1,2,...k,有Xij=Zj.比如Z=a,b,f,c是X=a,b,c,f,b,c的子序列.现在给出两个序列X和Y,任务是找到X和Y的最大公共子序列,也就是说要找到一个最长的序列Z,使得Z既是X的子序列也是Y的子序列.

Input 

输入包括多组测试数据.每组数据包括一行,给出两个长度不超过200的字符串,表示两个序列.两个字符串之间由若干个空格9.

Output 

对每组输入数据,输出一行,给出两个序列的最大公共子序列的长度.

Sample Input 

abcfbc  abfcab

programming contest

abcd mnp

Sample Output 

4

2

0

分析

 

 

Z[i][j]= {

      0  i=0或j=0;

      Z[i-1][j-1]+1  X[i]=Y[j];

      max{ Z[i-1][j] , Z[i][j-1] }  X[i]!=Y[j]

}

下标

 

0

1

2

3

4

5

6

 

Z[i][j]

 

a

b

c

f

b

c

0

 

0

0

0

0

0

0

0

1

a

0

1

1

1

1

1

1

2

b

0

1

2

2

2

2

2

3

f

0

1

2

2

3

3

3

4

c

0

1

2

3

3

3

4

5

a

0

1

2

3

3

3

4

6

b

0

1

2

3

3

4

4

 

XY下标从0开始,Z[i][j] 下标有效的从1开始

 

 1 #include<stdio.h> 2 #include<string.h> 3 char x[201]; 4 char y[201]; 5 int z[200][200]; 6 int main() 7 { 8    int i,j,s,t,max; 9    while(scanf("%s%s",x,y)!=EOF)10    { 11        s=strlen(x);t=strlen(y);12        for(i=0;i<s;i++)13            z[i][0]=0;14         for(j=0;j<t;j++)15            z[0][j]=0;16         for(i=1;i<=s;i++)17             for(j=1;j<=t;j++)18             {19                 if(x[i-1]==y[j-1]) z[i][j]=z[i-1][j-1]+1;20                 else 21                 {22                     if(z[i-1][j]>=z[i][j-1]) z[i][j]=z[i-1][j];23                     else   z[i][j]=z[i][j-1];24                 }25             }26 /*        max=z[0][0];27         for(i=0;i<=s;i++)28             for(j=0;j<=t;j++)29                 if(z[i][j]>max) max=z[i][j];*/ 30         printf("%d\n",z[s][t]);31    }32 33    return 0;34 }
View Code

 

Problem D:最长上升子序列

Time Limit:1000MS  Memory Limit:65536K
Total Submit:456 Accepted:239 

Description 

一个数的序列bi,b1<=b2<=b3..<=bn的时候,称这个序列是上升的。对于给定的一个序列(A1,A2,....,AN),可以得到一些上升的子序列(AI1,AI2,....AIK,这里1<=I1<=I2<=....<=IK<=N,比如,对于序列(1,7,3,5,9,4,8),有它的一些上升子序列,(1,7),(3,4,8).这些子序列中最长的长度是4,比如子序列(1,3,5,8). 
你的任务就是对于给定的序列,求出最长上升子序列的长度

Input 

输入有多个案例,每个案例占两行: 
第一行是序列的长度N(1<=N<=1000).第二行给出序列中的N个整数,这些整数的取值范围都在010000. 

Output 

最长上升子序列的长度.

Sample Input 

7

1 7 3 5 9 4 8

2

1036 3

Sample Output 

4

1

分析

设置b[N]b[i]表示序列的第1个数到第i个数(保留第i个数)的最长上升子序列的长度。

 

b[i]=max(b[j])+1(a[j]<a[i],1<=j<=i<=n)

如果a[i]最小,则b[i]=1

 

 

A

1

7

3

5

9

4

8

B

1

2

2

3

4

3

4

 

 1 #include<stdio.h> 2 int A[100],B[100]; 3 int main() 4 { 5     int n,i,j,max; 6     while(scanf("%d",&n)!=EOF) 7     { 8         for(i=0;i<n;i++) 9             scanf("%d",&A[i]);10         B[0]=1;11         for(i=1;i<n;i++)12         {13             max=0;14             for(j=0;j<i;j++)15                 if(A[j]<A[i]&&B[j]>max) max=B[j];16             B[i]= max+1;17             18         }19         max=B[0];20         for(i=1;i<n;i++)21             if(max<B[i]) max=B[i];22         printf("%d\n",max);23     }24     return 0;25 }
View Code

 

 

DP的简单应用