TEST 32-36

POJ 2228 Naptime

分析: 分两种情况
不是环形直接动态规划
是环形 加上第一个位置
然后用 一串来判断最优解
最后扫描 用一个 数把最大值存下

AC代码

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
const int maxn=3850;
using namespace std;
int n,m,map[maxn];
int dp[maxn][maxn];
int main(){
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        dp[i][j]=0;
        int ans=0;
        for(int i=1;i<=n;i++) 
        scanf("%d",&map[i]);
        for(int j=2;j<=m;j++){
            int mx=0;
            for(int i=j;i<=n;i++){
                dp[i][j]=max(mx,dp[i-1][j-1]+map[i]);
                mx=max(mx,dp[i-1][j-1]);
            }
        }
        for(int i=m;i<=n;i++)
        ans=max(ans,dp[i][m]);

        for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
        dp[i][j]=0;
        dp[2][2]=map[2];
        for(int j=3;j<=m;j++){
            int mx=0;
            for(int i=j;i<=n;i++){
                dp[i][j]=max(mx,dp[i-1][j-1]+map[i]);
                mx=max(mx,dp[i-1][j-1]);
            }
        }
        if(m>=2)
        ans=max(ans,dp[n][m]+map[1]);
        printf("%d\n",ans);
    }
    return 0;
}

POJ 2411 Mondriaan’s Dream

参考
状态压缩DP
这个题 就是要把横着放优先 这样才能保证最后一行不会出现竖着放的情况
将横着 按照 11 存 而 竖着的按照 0 1存
这样 最后一定覆盖满的状态 一定是
相邻的两行 相或 是1 相与 不是1 的个数是奇数(因为 如果是偶数的完全可以用横着来代替)

AC

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
long long dp[12][2050];
bool check(int s){
    int ret=0;
    while(s){
        if(s&1)ret++;
        else{
            if(ret&1)
            return 0;
            ret =0;
            }
            s>>=1;
    } 
    if(ret&1)return 0;
    return 1;
}
int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        if(n==0&&m==0) break;
        int tot=(1<<m);
        memset(dp,0,sizeof(dp));
        for(int i=0;i<tot;i++)
            if(check(i)) dp[1][i]=1;
        for(int i=1;i<n;i++)
        for(int j=0;j<tot;j++)
        if(dp[i][j]){
            for(int k=0;k<tot;k++)
                if( (j|k)==tot-1&& check(j&k) )
                    dp[i+1][k]+=dp[i][j];
            }
    printf("%I64d\n",dp[n][tot-1]);
    }
    return 0;
}

URAL 1018 Binary Apple Tree

树形DP
状态转移方程:f[i][j]=max(ans[leftchild][k]+f[rightchild][j-k-1])+value
就是 按照状态转移方程求出最大苹果树
如果没有标记 就记录左 儿子,标记了就记录右儿子
最后输出尾值就是最大值

AC代码

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
const int maxn =101;
struct edge{
    int t;
    int next;
    int v;
}a[2*maxn];
struct point{
    int l,r;
    int v;
}b[maxn];
int n,m;
int tot=0,last[maxn],f[maxn][maxn];
bool vis [maxn];
void add(int from,int to,int value)
{
      a[++tot].t=to;
      a[tot].v=value;
      a[tot].next=last[from];
      last[from]=tot;
}
void build(int now)
{
      vis[now]=true;
      for(int i=last[now];i;i=a[i].next)
      {
            if(!vis[a[i].t])
            {
                  if(!b[now].l)//没有的话 记录左儿子
                        b[now].l=a[i].t;
                  else  b[now].r=a[i].t;//否则记录右儿子<二叉树> 
                  b[a[i].t].v=a[i].v;
                  build(a[i].t);
            }
      }
}
int treedp(int now,int rest)
{
      if(!now || !rest)   return 0;
      if(f[now][rest])   return f[now][rest];
      for(int i=0;i<rest;i++)
            f[now][rest]=max(f[now][rest],treedp(b[now].l,i)+treedp(b[now].r,rest-i-1));
      f[now][rest]+=b[now].v;
      return f[now][rest];
}
int main()
{
	  scanf("%d%d",&n,&m);
	  for(int i=1;i<n;i++)
	  {
            int A,B,C;
            scanf("%d%d%d",&A,&B,&C);
            add(A,B,C);
            add(B,A,C);
      }
      build(1);//建树 
      printf("%d\n",treedp(1,m+1));
      return 0;
}
发布了55 篇原创文章 · 获赞 1 · 访问量 960

猜你喜欢

转载自blog.csdn.net/weixin_43556527/article/details/103514993
今日推荐