kuangbin专题十二 基础dp

kuangbin专题十二 基础dp

1. Max Sum Plus Plus

压缩一维避免超空间,维护前缀最大值将 O ( n 3 ) O(n^3) O(n3)降到 O ( n 2 ) O(n^2) O(n2)

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10,INF=0x7fffffff;
int n,m;
int a[N],f[N],Max[N];
int main()
{
   
   
    while(scanf("%d%d",&m,&n)!=EOF){
   
   
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        for(int i=0;i<=n;i++) f[i]=Max[i]=0;
        int cur;
        for(int j=1;j<=m;j++){
   
   
            cur=-INF;
            for(int i=j;i<=n;i++){
   
   
                f[i]=max(f[i-1],Max[i-1])+a[i];
                Max[i-1]=cur;
                cur=max(cur,f[i]);
            }
        }
        printf("%d\n",cur);
    }
    return 0;
}

2. Ignatius and the Princess IV

感觉像是题目放错了,用数组或者map记录个数就行。

#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
const int N=1e6+10;
int n,a[N];
unordered_map<int,int> num;
int main()
{
   
   
    while(scanf("%d",&n)!=EOF){
   
   
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        num.clear();
        for(int i=1;i<=n;i++){
   
   
            num[a[i]]++;
            if(num[a[i]]>=(n+1)/2){
   
   
                printf("%d\n",a[i]);
                break;
            }
        }
    }
    return 0;
}

相邻的HDU 1028刚好是个dp。分别可以用完全背包或分治的做法来做。

#include<bits/stdc++.h>
using namespace std;
const int N=130;
int f[N];
void init(){
   
   
    f[0]=1;
    for(int i=1;i<N;i++)
        for(int j=i;j<N;j++)
            f[j]+=f[j-i];
}
int main()
{
   
   
    init();
    int n;
    while(scanf("%d",&n)!=EOF){
   
   
        printf("%d\n",f[n]);
    }
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
const int N=130;
int f[N][N];
int calc(int a,int b){
   
   
    if(f[a][b]!=-1) return f[a][b];
    if(a<1||b<1) return f[a][b]=0;
    if(a==1||b==1) return f[a][b]=1;
    if(a==b) return f[a][b]=1+calc(a,b-1);
    if(a<b) return f[a][b]=calc(a,a);
    if(a>b) return f[a][b]=calc(a-b,b)+calc(a,b-1);
}
int main()
{
   
   
    memset(f,-1,sizeof f);
    int n;
    while(scanf("%d",&n)!=EOF){
   
   
        printf("%d\n",calc(n,n));
    }
    return 0;
}

3. Monkey and Banana

最长上升子序列模型题

#include<bits/stdc++.h>
using namespace std;
const int N=200;
struct Block{
   
   
    int x,y,z;
    bool operator >(const Block &t)const{
   
   
        if(x!=t.x) return x>t.x;
        return y>t.y;
    }
};
int f[N];
int n;
int main()
{
   
   
    int T=0;
    while(scanf("%d",&n),n){
   
   
        vector<Block> v;
        for(int i=1;i<=n;i++){
   
   
            int a,b,c;
            scanf("%d%d%d",&a,&b,&c);
            v.push_back({
   
   a,b,c});
            v.push_back({
   
   a,c,b});
            v.push_back({
   
   b,a,c});
            v.push_back({
   
   b,c,a});
            v.push_back({
   
   c,a,b});
            v.push_back({
   
   c,b,a});
        }
        sort(v.begin(),v.end(),greater<Block>());
        int res=0;
        for(int i=0;i<v.size();i++){
   
   
            f[i]=v[i].z;
            for(int j=0;j<i;j++){
   
   
                if(v[i].x<v[j].x&&v[i].y<v[j].y){
   
   
                     f[i]=max(f[i],f[j]+v[i].z);
                }
            }
            res=max(res,f[i]);
        }
        printf("Case %d: maximum height = %d\n",++T,res);
    }
    return 0;
}

4. Doing Homework

很巧妙的状压dp。

#include<bits/stdc++.h>
using namespace std;
const int N=16;
struct Subject{
   
   
    char name[110];
    int last,d;
}a[N];
int n;
int f[1<<N],pre[1<<N];
void output(int u){
   
   
    if(pre[u]!=0) output(pre[u]);
    for(int i=0;i<n;i++){
   
   
        if(u>>i&1^pre[u]>>i&1){
   
   
            printf("%s\n",a[i].name);
            break;
        }
    }
}
int main()
{
   
   
    int T;
    scanf("%d",&T);
    while(T--){
   
   
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%s%d%d",a[i].name,&a[i].last,&a[i].d);
        memset(f,0x3f,sizeof f);
        f[0]=0;
        for(int i=0;i<1<<n;i++){
   
   
            int sum=0;
            for(int j=0;j<n;j++)
                if(i>>j&1) sum+=a[j].d;
            for(int j=0;j<n;j++){
   
   
                if(i>>j&1) continue;
                int temp=max(0,sum+a[j].d-a[j].last);
                int k=i|(1<<j);
                if(f[k]>f[i]+temp){
   
   
                    f[k]=f[i]+temp;
                    pre[k]=i;
                }
            }
        }
        printf("%d\n"<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值