pku ppt some problem

The Triangle  http://poj.org/problem?id=1163

暴力dfs的话,每个节点有两条路可以走,那么n个节点复杂度就是2^n  n=100  超时   dp来做 就优化成 n^2

记忆化搜索,就能优化成n^2 因为一个点最多算一次,以后会直接返回dp i j 。 dp i j 表示这个位置能获得最大值。最后一行就是a i j  ,其他行都可以由下面两条路取最大值。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define mt(a,b) memset(a,b,sizeof(a))
 5 using namespace std;
 6 const int M=128;
 7 int n,a[M][M],dp[M][M];
 8 int dfs(int i,int j){
 9     if(~dp[i][j]) return dp[i][j];
10     if(i==n) dp[i][j]=a[i][j];
11     else     dp[i][j]=max(dfs(i+1,j),dfs(i+1,j+1))+a[i][j];
12     return dp[i][j];
13 }
14 int main(){
15     while(~scanf("%d",&n)){
16         for(int i=1;i<=n;i++){
17             for(int j=1;j<=i;j++){
18                 scanf("%d",&a[i][j]);
19             }
20         }
21         mt(dp,-1);
22         printf("%d\n",dfs(1,1));
23     }
24     return 0;
25 }
View Code

自底向上的推法,那dp i j 就表示i j 这个位置能获得的最大值, 然后dp i j 可以推向两个状态,分别是 dp i-1 j 和 dp i-1 j-1.  这是用当前状态去推能到达的所有状态的写法。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define mt(a,b) memset(a,b,sizeof(a))
 5 using namespace std;
 6 const int M=128;
 7 int a[M][M],dp[M][M];
 8 int main(){
 9     int n;
10     while(~scanf("%d",&n)){
11         for(int i=1;i<=n;i++){
12             for(int j=1;j<=i;j++){
13                 scanf("%d",&a[i][j]);
14             }
15         }
16         mt(dp,0);
17         for(int i=n+1;i>=1;i--){
18             for(int j=1;j<=n;j++){
19                 dp[i-1][j]=max(dp[i-1][j],dp[i][j]+a[i-1][j]);
20                 dp[i-1][j-1]=max(dp[i-1][j-1],dp[i][j]+a[i-1][j-1]);
21             }
22         }
23         printf("%d\n",dp[1][1]);
24     }
25     return 0;
26 }
View Code

 这是用所有能到达的状态推当前状态的写法,并且空间优化了一下,省去了输入的数组。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int M=128;
 5 int dp[M][M];
 6 int main(){
 7     int n;
 8     while(~scanf("%d",&n)){
 9         for(int i=1;i<=n;i++){
10             for(int j=1;j<=i;j++){
11                 scanf("%d",&dp[i][j]);
12             }
13         }
14         for(int i=n-1;i>=1;i--){
15             for(int j=1;j<=i;j++){
16                 dp[i][j]=max(dp[i+1][j],dp[i+1][j+1])+dp[i][j];
17             }
18         }
19         printf("%d\n",dp[1][1]);
20     }
21     return 0;
22 }
View Code

 

 

最长上升子序列  http://bailian.openjudge.cn/practice/2757/

记忆化搜索

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int M=1024;
 5 int n,a[M],dp[M];
 6 int dfs(int i){
 7     if(~dp[i]) return dp[i];
 8     dp[i]=1;
 9     for(int j=i+1;j<=n;j++){
10         if(a[i]<a[j]){
11             dp[i]=max(dp[i],dfs(j)+1);
12         }
13     }
14     return dp[i];
15 }
16 int main(){
17     while(~scanf("%d",&n)){
18         for(int i=1;i<=n;i++){
19             scanf("%d",&a[i]);
20             dp[i]=-1;
21         }
22         int ans=0;
23         for(int i=1;i<=n;i++){
24             ans=max(ans,dfs(i));
25         }
26         printf("%d\n",ans);
27     }
28     return 0;
29 }
View Code

 

 用dp【i】表示以 i 为结尾的最长上升子序列的长度,可以得到它可以由前面所有值比他小的dp +1推过来。这是当前状态由其他所有能推过来的状态更新的写法。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int M=1024;
 5 int a[M],dp[M];
 6 int main(){
 7     int n;
 8     while(~scanf("%d",&n)){
 9         for(int i=1;i<=n;i++){
10             scanf("%d",&a[i]);
11             dp[i]=1;
12         }
13         int ans=0;
14         for(int i=1;i<=n;i++){
15             for(int j=1;j<=i;j++){
16                 if(a[j]<a[i]){
17                     dp[i]=max(dp[i],dp[j]+1);
18                 }
19             }
20             ans=max(ans,dp[i]);
21         }
22         printf("%d\n",ans);
23     }
24     return 0;
25 }
View Code

 

 还是用dp【i】表示以 i 为结尾的最长上升子序列的长度,由当前状态去更新其他所有能更新的状态的写法。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int M=1024;
 5 int a[M],dp[M];
 6 int main(){
 7     int n;
 8     while(~scanf("%d",&n)){
 9         for(int i=1;i<=n;i++){
10             scanf("%d",&a[i]);
11             dp[i]=1;
12         }
13         for(int i=1;i<=n;i++){
14             for(int j=i+1;j<=n;j++){
15                 if(a[i]<a[j]){
16                     dp[j]=max(dp[j],dp[i]+1);
17                 }
18             }
19         }
20         int ans=0;
21         for(int i=1;i<=n;i++){
22             ans=max(ans,dp[i]);
23         }
24         printf("%d\n",ans);
25     }
26     return 0;
27 }
View Code

 

 

 

Common Subsequence http://poj.org/problem?id=1458

用dp i j 表示a串以 i 结尾  b串 以 j 结尾的最长公共子序列长度,这个是当前状态通过其他所有状态推来的写法。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define mt(a,b) memset(a,b,sizeof(a))
 5 using namespace std;
 6 const int M=512;
 7 char a[M],b[M];
 8 int dp[M][M];
 9 int main(){
10     while(~scanf("%s%s",a,b)){
11         mt(dp,0);
12         int n=strlen(a);
13         int m=strlen(b);
14         for(int i=1;i<=n;i++){
15             for(int j=1;j<=m;j++){
16                 if(a[i-1]==b[j-1]){
17                     dp[i][j]=max(dp[i][j],dp[i-1][j-1]+1);
18                 }
19                 else{
20                     dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
21                 }
22             }
23         }
24         printf("%d\n",dp[n][m]);
25     }
26     return 0;
27 }
View Code

 

 

 

2755:神奇的口袋 http://bailian.openjudge.cn/practice/2755/

二进制枚举,暴力。

 1 #include<cstdio>
 2 const int M=32;
 3 int a[M];
 4 int main(){
 5     int n;
 6     while(~scanf("%d",&n)){
 7         for(int i=0;i<n;i++){
 8             scanf("%d",&a[i]);
 9         }
10         int all=1<<n,ans=0;
11         for(int i=0;i<all;i++){
12             int sum=0;
13             for(int j=0;j<n;j++){
14                 if((i>>j)&1) sum+=a[j];
15             }
16             if(sum==40) ans++;
17         }
18         printf("%d\n",ans);
19     }
20     return 0;
21 }
View Code

 dfs枚举,暴力

 1 #include<cstdio>
 2 const int M=32;
 3 int a[M],ans,n;
 4 bool use[M];
 5 void dfs(int t){
 6     if(t==n){
 7         int sum=0;
 8         for(int i=0;i<n;i++){
 9             if(use[i]) sum+=a[i];
10         }
11         if(sum==40) ans++;
12         return ;
13     }
14     use[t]=true;
15     dfs(t+1);
16     use[t]=false;
17     dfs(t+1);
18 }
19 int main(){
20     while(~scanf("%d",&n)){
21         for(int i=0;i<n;i++){
22             scanf("%d",&a[i]);
23         }
24         ans=0;
25         dfs(0);
26         printf("%d\n",ans);
27     }
28     return 0;
29 }
View Code

 dfs直接找解,递归,不用递归sum,k-1,用了递归sum-ak,k-1 

 1 #include<cstdio>
 2 int a[32];
 3 int dfs(int sum,int k){///return 前k个物品选和为sum的情况
 4     if(sum==0) return 1;
 5     if(k<=0) return 0;
 6     return dfs(sum,k-1)+dfs(sum-a[k],k-1);
 7 }
 8 int main(){
 9     int n;
10     while(~scanf("%d",&n)){
11         for(int i=1;i<=n;i++){
12             scanf("%d",&a[i]);
13         }
14         printf("%d\n",dfs(40,n));
15     }
16     return 0;
17 }
View Code

 dp递推的找解,定义方式和上面一种一样,dp i j 表示前 i 个 和为 j 的情况,这个是由选和不选两种推出两个转移方程。

 1 #include<cstdio>
 2 #include<cstring>
 3 #define mt(a,b) memset(a,b,sizeof(a))
 4 int a[32];
 5 int dp[32][64];
 6 int main(){
 7     int n;
 8     while(~scanf("%d",&n)){
 9         for(int i=1;i<=n;i++){
10             scanf("%d",&a[i]);
11         }
12         mt(dp,0);
13         dp[0][0]=1;
14         for(int i=1;i<=n;i++){
15             for(int j=0;j<=40;j++){
16                 dp[i][j]+=dp[i-1][j];
17                 if(j+a[i]<=40)
18                 dp[i][j+a[i]]+=dp[i-1][j];
19             }
20         }
21         printf("%d\n",dp[n][40]);
22     }
23     return 0;
24 }
View Code

 与上一dp相同,空间少了一维,我们只需知道某个和能达到的次数,所以输入一个个去更新所有的情况就行。这是由当前状态推向下一状态的写法。

 1 #include<cstdio>
 2 #include<cstring>
 3 #define mt(a,b) memset(a,b,sizeof(a))
 4 int dp[64];
 5 int main(){
 6     int n,a;
 7     while(~scanf("%d",&n)){
 8         mt(dp,0);
 9         for(int i=1;i<=n;i++){
10             scanf("%d",&a);
11             for(int j=40;j>=1;j--){
12                 if(dp[j]&&j+a<=40){
13                     dp[j+a]+=dp[j];
14                 }
15             }
16             dp[a]++;
17         }
18         printf("%d\n",dp[40]);
19     }
20     return 0;
21 }
View Code

 

 

 

 

end

posted on 2014-09-14 10:05  gaolzzxin  阅读(137)  评论(0编辑  收藏  举报