• 挑战程序设计竞赛2.3节习题选解


    poj2385

    题目链接:https://vjudge.net/problem/POJ-2385

    设dp[i][j]表示经过i秒移动了j次能接到的最多苹果数,则dp[i][j]=max(dp[i][j],dp[i-k][j-1]+sum[i][j%2+1]-sum[i-k][j%2+1]);(第i-k秒从一棵树移动到另一棵树,之后在另一棵树下不动)tree[i][1]=1表示第i秒第一棵树掉下来一个苹果,tree[i][2]=1同理,tree[i][1]或tree[i][2]=0表示当前的树不掉苹果,sum[i][1]和sum[i][2]分别为tree[i][1]和tree[i][2]的前缀和,用这个求出在一段时间内在某一棵树底下不移动时,能拿到多少苹果

     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=100+10;
     6 const int maxw=30+10;
     7 int main()
     8 {
     9     int tree[maxn][3],sum[maxn][3];
    10     int dp[maxn][maxw];
    11     int i,j,k,t,n,w,s,ans,x;
    12     cin>>n>>w;
    13     memset(tree,0,sizeof(tree));memset(sum,0,sizeof(sum));
    14     for (i=1;i<=n;i++)
    15       {
    16           cin>>x;
    17           if (x==1) tree[i][1]=1;else tree[i][2]=1;
    18       }
    19     for (i=1;i<=n;i++)
    20       {
    21           sum[i][1]=sum[i-1][1]+tree[i][1];
    22           sum[i][2]=sum[i-1][2]+tree[i][2];
    23       }
    24     memset(dp,0,sizeof(dp));
    25     for (i=1;i<=n;i++) dp[i][0]=sum[i][1];
    26     for (i=1;i<=n;i++)
    27       for (j=1;j<=min(i,w);j++)
    28         for (k=1;k<=i-j+1;k++)
    29           dp[i][j]=max(dp[i][j],dp[i-k][j-1]+sum[i][j%2+1]-sum[i-k][j%2+1]);
    30     ans=0;
    31     for (i=0;i<=w;i++) ans=max(ans,dp[n][i]);
    32     cout<<ans<<endl;
    33     return 0;
    34 } 
    poj2385

    poj3616

    题目链接:https://vjudge.net/problem/POJ-3616

    LIS问题的变形。用f[i]表示到第i个区间内最高的价值,dp[i]=max(dp[i],dp[j]+a[j].v),若j的右边端点<=i的左边端点

    当然,要先按开始时间(左端点)排个序

    #include<iostream>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int maxm=100+10;
    struct node
    {
        int l,r,v;
    }a[maxm];
    bool cmp(node p,node q)
    {
        return p.l<q.l;
    }
    int main()
    {
        int i,j,k,n,m,rr,ans;
        int dp[maxm];
        cin>>n>>m>>rr;
        for (i=1;i<=m;i++) cin>>a[i].l>>a[i].r>>a[i].v;
        sort(a+1,a+m+1,cmp);
        memset(dp,0,sizeof(dp));
        for (i=1;i<=m;i++) dp[i]=a[i].v;
        for (i=1;i<=m;i++)
          for (j=1;j<=i-1;j++)
            if (a[j].r+rr<=a[i].l) dp[i]=max(dp[i],dp[j]+a[i].v);
        ans=0;
        for (i=1;i<=m;i++) ans=max(ans,dp[i]);
        cout<<ans<<endl;
        return 0;
    }
    poj3616

    poj3280题解:https://www.cnblogs.com/edmunds/p/12783673.html

    poj1742题解:https://www.cnblogs.com/edmunds/p/12442642.html

    poj3046:

    题目链接:https://vjudge.net/problem/POJ-3046

    2.3节多重集组合数的练习题,基本和例题一样。设dp[i][j]表示选到第i种,一共选出了j个的方案数

    可以很容易写出一个转移方程:dp[i][j]=dp[i-1][j]+dp[i-1][j-1]+...+dp[i-1][j-min(a[i],j)]

    但是这样会时间复杂度过高。注意这一段 dp[i-1][j-1]+...+dp[i-1][j-min(a[i],j)]应该和dp[i][j-1]有关系。下面分情况讨论:

    1) 若a[i]>=j,dp[i][j]=dp[i-1][j]+(dp[i-1][j-1]+...+dp[i-1][0])=dp[i-1][j]+dp[i][j-1];

    2) 若a[i]<j,dp[i][j]=dp[i-1][j]+(dp[i-1][j-1]+...+dp[i-1][j-a[i]])=dp[i-1][j]+dp[i][j-1]-dp[i-1][j-a[i]-1]

    这样递推的时间复杂度就降到O(T*A)

    注意取模。我也不知道为啥一开始算出来是负数,然后在第二个递推式子里加上一个mod再模mod就对了......按理说应该不可能会算出来负数的啊??

    还要注意边界:dp[i][0]=1;i=0-t

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int mod=1e6;
    const int maxt=100+10;
    const int maxa=1000+10;
    
    int dp[maxt][maxa],num[maxt];
    int t,a,s,b,i,j,ans,k,x;
    
    int main(){
        //freopen("poj3046.txt","r",stdin);
        cin>>t>>a>>s>>b;
        memset(num,0,sizeof(num));
        for (i=1;i<=a;i++){
            cin>>x;num[x]++;
        }
        memset(dp,0,sizeof(dp));
        for (i=0;i<=t;i++) dp[i][0]=1;
        for (i=1;i<=t;i++)
          for (j=1;j<=a;j++){
              if (num[i]>=j) dp[i][j]=(dp[i-1][j]+dp[i][j-1])%mod;
              else dp[i][j]=(dp[i-1][j]+dp[i][j-1]-dp[i-1][j-num[i]-1]+mod)%mod;
          }
        ans=0;
        for (i=s;i<=b;i++) ans=(ans+dp[t][i])%mod;
        cout<<ans<<endl;
        //fclose(stdin);
        return 0;
    }
    poj3046

     另外,如果空间不够(比如poj1742那样),可以用滚动数组优化,因为注意到dp[i][j]只和dp[i][...]和dp[i-1][...]有关

     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxt=3000+10;
     6 const int mod=1000000;
     7 int main()
     8 {
     9     int n,i,j,k,t,b,ans,s,m;
    10     int a[maxt],f[2][maxt];
    11     cin>>t>>n>>s>>b;
    12     memset(a,0,sizeof(a));
    13     for (i=1;i<=n;i++) {
    14           cin>>k;a[k]++;
    15        } 
    16     ans=0;
    17     memset(f,0,sizeof(f));
    18     for (i=0;i<=1;i++) f[i][0]=1;
    19     for (i=1;i<=t;i++)
    20           for (j=1;j<=b;j++){             
    21               if (j>a[i]) f[i%2][j]=(f[(i-1)%2][j]+f[i%2][j-1]-f[(i-1)%2][j-1-a[i]]+mod)%mod;  //滚动数组 
    22             else f[i%2][j]=(f[(i-1)%2][j]+f[i%2][j-1])%mod;
    23         }
    24     for (i=s;i<=b;i++) ans=(ans+f[t%2][i])%mod;
    25     cout<<ans<<endl;
    26     return 0;
    27 }
    poj3046,滚动数组

    poj1065

    题目链接:https://vjudge.net/problem/POJ-1065

    套路题。对一个端点排序后,由dilworth定理对另一个端点求最长严格下降子序列即可

     1 #include<iostream>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int maxn=500+10;
     6 struct node{int l,w;};int f[maxn];
     7 node a[maxn];
     8 bool cmp(node p,node q){
     9     if (p.l==q.l) return p.w<q.w;
    10     else return p.l<q.l;
    11 }
    12 int main()
    13 {
    14     int i,j,k,ans,t,n;
    15     //freopen("poj1065.txt","r",stdin);
    16     cin>>t;
    17     while (t--){
    18           cin>>n;
    19           memset(f,0,sizeof(f));
    20           for (i=1;i<=n;i++) cin>>a[i].l>>a[i].w;
    21           sort(a+1,a+n+1,cmp);
    22           f[1]=1;
    23         for (i=2;i<=n;i++){
    24           f[i]=1; 
    25           for (j=1;j<=i-1;j++)
    26             if (a[j].w>a[i].w) f[i]=max(f[i],f[j]+1);
    27         }
    28         ans=0;
    29         for (i=1;i<=n;i++) ans=max(ans,f[i]);
    30         cout<<ans<<endl;
    31        } 
    32     //fclose(stdin);
    33     return 0;
    34 }
    poj1065

    poj1631以前做过了......还是求LIS的问题

    poj3666题解:https://www.cnblogs.com/edmunds/p/12306923.html

    poj2392题解:https://www.cnblogs.com/edmunds/p/12783660.html

    poj2184题解:https://www.cnblogs.com/edmunds/p/12783708.html

  • 相关阅读:
    POJ 3616 Milking Time(简单DP)
    POJ 2954 Triangle(计算几何Pick定理)
    POJ 3664 Election Time(简单的快速排序)
    POJ 2007 Scrambled Polygon(计算几何凸包)
    POJ 3673 Cow Multiplication(简单数学)
    POJ 3663 Costume Party (快速排序)
    计算几何模板(一)
    [转]Silverlight中使用MVVM(3)
    Silverlight中使用MVVM(2)
    Silverlight使用Binding动态绑定数据
  • 原文地址:https://www.cnblogs.com/edmunds/p/12659741.html
Copyright © 2020-2023  润新知