dp专题

1.花店橱窗

原题链接:https://ac.nowcoder.com/acm/contest/87275/1005

注意放与不放是平行的

查看代码

#include <bits/stdc++.h>
#define int long long
using namespace  std;
int va[110][110];
int f[1000000];
struct node
{
    int a[110];
    int t;
}way[110][110];//记录路径
signed main()
{
    int n,m;
    cin>>n>>m;
    vector<vector<int >> dp(105,vector<int>(105,-LLONG_MAX));
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=m;j++)
        {
            cin>>va[i][j];
        }
    }
    for(int i=0;i<=m;i++)
    {
        dp[0][i]=0;
    }
    for(int i=1;i<=n;i++)//第i束花是否放到第j个瓶
    {
        for(int j=i;j<=m;j++)
        {
            if(dp[i-1][j-1]+va[i][j]>dp[i][j-1])//是
            {
                way[i][j]=way[i-1][j-1];
                way[i][j].a[++way[i][j].t]=j;
                dp[i][j]=dp[i-1][j-1]+va[i][j];
            }
            else//否
            {
                way[i][j]=way[i][j-1];
                dp[i][j]=dp[i][j-1];
            }
        }
    }
    cout<<dp[n][m]<<endl;
    for(int i=1;i<=way[n][m].t;i++)
        cout<<way[n][m].a[i]<<" ";
    return 0;
}

2.过河卒

原题链接:https://ac.nowcoder.com/acm/contest/87275/1007

板子题

查看代码
 #include<bits/stdc++.h>
using namespace std;
#define int long long
int dp[100][100];
signed main()
{
    int a,b,c,d;
    cin>>a>>b>>c>>d;
    for(int i=0;i<=a;i++)
    {
        for(int j=0;j<=b;j++)
        {
            if((i-c)*(i-c)+(j-d)*(j-d)==5||(i==c&&j==d))dp[i][j]=0;
            else
            {
                if(i==0&&j==0)dp[i][j]=1;
                else
                {
                    if(i==0)dp[i][j]+=dp[i][j-1];
                    else if(j==0)dp[i][j]+=dp[i-1][j];
                    else dp[i][j]=dp[i-1][j]+dp[i][j-1];
                }
            }
        }
    }
    cout<<dp[a][b];
    return 0;
}

3.传球游戏

原题链接:https://ac.nowcoder.com/acm/contest/87275/1008

注意在第一个人和第n个人的时候,因为是个圈

查看代码
 #include <bits/stdc++.h>
#define int long long
using namespace  std;
int a[1000000];
signed main()
{
    int n,m;
    cin>>n>>m;
    vector<vector<int >> dp(m+1,vector<int>(n+1,0));
    dp[0][1]=1;
    for(int i=1;i<=m;i++)//第i次传球后球在j手中的方法数
    {
        for(int j=1;j<=n;j++)
        {
            if(j==1)dp[i][j]=dp[i-1][n]+dp[i-1][j+1];
            else if(j==n)dp[i][j]=dp[i-1][j-1]+dp[i-1][1];
            else dp[i][j]=dp[i-1][j-1]+dp[i-1][j+1];
        }
    }
    cout<<dp[m][1];
    return 0;
}

4.[NOIP1999]拦截导弹

原题链接:https://ac.nowcoder.com/acm/contest/87275/1011

最长上升子序列问题

查看代码
 #include <bits/stdc++.h>
using namespace std;
vector<int>a;
int dp[10010];
int g[1000000];
int main() {
    string n;
    while(cin>>n){
        if(n=="\n")break;
        int t=stol(n);
        a.push_back(t);
    }
    reverse(a.begin(),a.end());
    //for(int i=0;i<a.size();i++)cout<<a[i]<<" ";
    for(int i=0;i<a.size();i++){
        dp[i]=1;
    }
    int ans=1,res=0;
    for(int i=1;i<a.size();i++){
        for(int j=0;j<i;j++){
            if(a[j]<a[i]){
                dp[i]=max(dp[i],dp[j]+1);
            }
            ans=max(ans,dp[i]);
        }
    }
    reverse(a.begin(),a.end());
    for(int i=0;i<a.size();i++)
    {
        int k=0;
        while(k<res&&g[k]<a[i])k++;
        g[k]=a[i];
        if(k>=res)res++;
    }
    cout<<ans<<endl;
    cout<<res;
    return 0;
}

5.[NOIP2004]合唱队形

原题链接;https://ac.nowcoder.com/acm/contest/87275/1010

最长上升子序列和最长下降子序列拼一起

查看代码
 #include <bits/stdc++.h>
using namespace std;
int a[1000000];
int MAX;
int dp[10010],fp[10010];
int main() {
    int n;
    cin>>n;
    for(int i=0;i<n;i++)cin>>a[i];
    for(int i=0;i<n;i++){
        dp[i]=1;
    }
    int ans=1;
    for(int i=1;i<n;i++){
        for(int j=0;j<i;j++){
            if(a[j]<a[i]){
                dp[i]=max(dp[i],dp[j]+1);
            }
        }
    }
    for(int i=n;i>=1;i--){
        for(int j=n;j>i;j--){
            if(a[j]<a[i]){
                fp[i]=max(fp[i],fp[j]+1);
            }
        }
        MAX=max(MAX,dp[i]+fp[i]-1);//同一个位置的上升和下降子序列加一起再减去重叠的自己
    }
    cout<<n-MAX<<endl;
    return 0;
}

6.装箱问题

原题链接:https://ac.nowcoder.com/acm/contest/87275/1016

板板

查看代码
 #include <bits/stdc++.h>
#define int long long
using namespace  std;
int a[1000000];
signed main()
{
    int v,n;
    cin>>v>>n;
    for(int i=1;i<=n;i++)cin>>a[i];
    vector<int> dp(v + 1, 0);
    dp[0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=v;j>=a[i];j--)
        {
            if(dp[j-a[i]])dp[j]=dp[j-a[i]];
        }
    }
    int ans=0;
    for(int i=v;i>=0;i--)
    {
        if(dp[i])
        {
            ans=i;
            break;
        }
    }
    cout<<v-ans;
    return 0;
}

7.小A买彩票

原题链接:https://ac.nowcoder.com/acm/contest/87275/1013

有点类似装箱问题,只不过是要计算方案数

查看代码
 #include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1001;
int n,m;
int v[N],w[N];
int f[N][N];
int gcd(int a,int b){
    return b==0?a:gcd(b,a%b);
}
signed main()
{
    cin>>n;
    f[0][0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=i;j<=4*i;j++)
        {
            for(int k=1;k<=4;k++)
            {
                if(j>=k)
                f[i][j]+=f[i-1][j-k];
            }
        }
    }
    int ans=0;
    for(int i=3*n;i<=4*n;i++)
        ans+=f[n][i];
    int sum=pow(4,n);
    int p=gcd(ans,sum);
    cout<<ans/p<<"/"<<sum/p;
    return 0;
}

8.CSL分苹果

原题链接:https://ac.nowcoder.com/acm/contest/87275/1019

装箱问题变形,就是把容量砍了一半

查看代码
 #include <bits/stdc++.h>
#define int long long
using namespace  std;
int a[1000000];
signed main()
{
    int n;
    cin>>n;
    int v1=0;
    for(int i=1;i<=n;i++)cin>>a[i],v1+=a[i];
    int v=v1/2;
    vector<int> dp(v + 1, 0);
    dp[0]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=v;j>=a[i];j--)
        {
            if(dp[j-a[i]])dp[j]=dp[j-a[i]];
        }
    }
    int ans=0;
    for(int i=v;i>=0;i--)
    {
        if(dp[i])
        {
            ans=i;
            break;
        }
    }
    cout<<ans<<" "<<v1-ans;
    return 0;
}

9.石子合并

原题链接:https://ac.nowcoder.com/acm/contest/87275/1024

板板,但是是圈状石子合并问题

查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=0x3f3f3f3f;
int dp[300][300],fp[300][300];
int a[300],b[300];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
        a[i+n]=a[i];
    }
    for(int i=1;i<=2*n;i++)
    {
        b[i]=b[i-1]+a[i];
    }
    for(int i=2*n-1;i>=1;i--) {
        for (int j=i+1;j<i+n;j++) {
                dp[i][j]=N;
                for (int k = i; k < j; k++) {//从k处断开,分别计算,达到一个递归的效果
                    dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + b[j] - b[i - 1]);
                    fp[i][j] = max(fp[i][j], fp[i][k] + fp[k + 1][j] + b[j] - b[i - 1]);
                }
            }
    }
    int ma=0,mi=N;
    for(int i=1;i<=n;i++)
    {
        ma=max(ma,fp[i][i+n-1]);
        mi=min(mi,dp[i][i+n-1]);
    }
    cout<<mi<<endl;
    cout<<ma<<endl;
    return 0;
}

带状如下

查看代码
 #include<bits/stdc++.h>
using namespace std;
const int N=0x3f3f3f3f;
int dp[300][300],fp[300][300];
int a[300],b[300];
int main(){
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    for(int i=1;i<=n;i++)
    {
        b[i]=b[i-1]+a[i];
    }
    for(int i=n-1;i>=1;i--) {
        for (int j=i+1;j<i+n;j++) {
                dp[i][j]=N;
                for (int k = i; k < j; k++) {
                    dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + b[j] - b[i - 1]);
                    //fp[i][j] = max(fp[i][j], fp[i][k] + fp[k + 1][j] + b[j] - b[i - 1]);
                }
            }
    }
    cout<<dp[1][n];
    //cout<<mi<<endl;
    //cout<<ma<<endl;
    return 0;
}

10.失衡天平

原题链接:https://ac.nowcoder.com/acm/contest/87275/1020

01背包问题,比一般要复杂的是放的情况有两种

查看代码
 #include <bits/stdc++.h>
#define int long long//背包
using namespace  std;
int dp[111][11100];
int a[1000000];
signed main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    memset(dp,-0x3f3f3f3f,sizeof dp);
    dp[0][0]=0;
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=10000;j++)
        {
            dp[i][j]=max({dp[i-1][j],dp[i-1][abs(j-a[i])]+a[i],dp[i-1][j+a[i]]+a[i]});
        } //三种情况分别为,不放,放在较轻的一端,放在较重的一段
    }
    int ans=0;
    for(int i=0;i<=m;i++)
    {
        ans=max(ans,dp[n][i]);
    }
    cout<<ans;
    return 0;
}
posted @ 2024-07-27 14:48  伊芙加登  阅读(17)  评论(0编辑  收藏  举报