动态规划练习们~

先学习了一下状丫 找了几个比较简单的题

/*codevs 2596 售货员难题 状丫dp */
#include<cstdio>
#include<cstring>
#define maxn 50010
using namespace std;
int n,g[20][20],f[maxn][20],ans;
int min(int x,int y){
    return x<y?x:y;
}
int main()
{
    scanf("%d",&n);n--;
    memset(f,127/3,sizeof(f));
    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
            scanf("%d",&g[i][j]);
    ans=f[0][0];f[0][0]=0;
    for(int i=1;i<(1<<n);i++)
        for(int j=1;j<=n;j++)if(i&(1<<j-1))
            for(int k=0;k<=n;k++)
                f[i][j]=min(f[i][j],f[i-(1<<j-1)][k]+g[k][j]);
    for(int i=1;i<=n;i++)
        ans=min(ans,f[(1<<n)-1][i]+g[i][0]);
    printf("%d
",ans);
    return 0;
}
/*codevs 2800 送外卖 状丫dp 有个数据有点问题 2333*/
#include<cstdio>
#include<cstring>
#define maxn 40010
using namespace std;
int n,g[16][16],f[maxn][16],ans;
int min(int x,int y){
    return x<y?x:y;
}
int main()
{
    scanf("%d",&n);
    memset(f,127/3,sizeof(f));
    for(int i=0;i<=n;i++)
        for(int j=0;j<=n;j++)
            scanf("%d",&g[i][j]);
    for(int k=0;k<=n;k++)
        for(int i=0;i<=n;i++)
            for(int j=0;j<=n;j++)
                g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
    ans=f[0][0];f[0][0]=0;
    for(int i=1;i<(1<<n);i++)
        for(int j=1;j<=n;j++)if(i&(1<<j-1))
            for(int k=0;k<=n;k++)
                f[i][j]=min(f[i][j],f[i-(1<<j-1)][k]+g[k][j]);
    for(int i=1;i<=n;i++)
        ans=min(ans,f[(1<<n)-1][i]+g[i][0]);
    printf("%d
",ans);
    return 0;
}
/*codevs 1358  状丫dp*/
#include<cstdio>
#include<cstring>
#define maxn 1500
using namespace std;
int g[12][12],f[12][12][maxn],ans;
int min(int x,int y){
    return x<y?x:y;
}
int main()
{
    for(int i=1;i<=10;i++)
        for(int j=1;j<=10;j++)
            scanf("%d",&g[i][j]);
    memset(f,127/3,sizeof(f));
    f[1][1][1<<g[1][1]]=g[1][1];
    int mxx=1<<10,SS;
    for(int i=1;i<=10;i++)
        for(int j=1;j<=10;j++)
            for(int S=0;S<mxx;S++){
                SS=S|(1<<g[i+1][j]);
                f[i+1][j][SS]=min(f[i+1][j][SS],f[i][j][S]+g[i+1][j]);
                SS=S|(1<<g[i][j+1]);
                f[i][j+1][SS]=min(f[i][j+1][SS],f[i][j][S]+g[i][j+1]);
            }
    printf("%d
",f[10][10][mxx-1]);
    return 0; 
} 
/*codevs 2594 状丫 dp */
#include<cstdio>
#define inf 1e8
#define maxn 2500
using namespace std;
int n,m,g[110][11],f[maxn];
int min(int x,int y){
    return x<y?x:y;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&g[i][j]);
    for(int i=0;i<=(1<<n);i++)
        f[i]=inf;
    f[0]=0;
    for(int i=0;i<(1<<n);i++)
        for(int j=1;j<=m;j++){
            int S=i;
            for(int k=1;k<=n;k++){
                if(g[j][k]==0)continue;
                if(g[j][k]==1)S=S|(1<<k-1);
                if(g[j][k]==-1&&S&(1<<k-1))
                    S-=(1<<k-1);
            }
            f[S]=min(f[S],f[i]+1);
        }
    if(f[(1<<n)-1]==inf)printf("The patient will be dead.
");
    else printf("%d
",f[(1<<n)-1]);
    return 0;
}

然后解决了历史遗留问题 现在看很简单吗似乎

/*codevs 1339 背包dp + 最丑的高精2333*/
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,t,W[25],cnt,f[25][25][510],dp[510],money[110],ans1[210],ans2[210];
char s[110];
int init(){
    int x=0;char s=getchar();
    while(s<'0'||s>'9')s=getchar();
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x;
}
int max(int x,int y){
    return x>y?x:y;
}
void mul1(int x){
    ans1[0]=money[0];
    for(int i=1;i<=ans1[0];i++)
        ans1[i]=money[i]*x;
    for(int i=1;i<=ans1[0];i++)
        if(ans1[i]>9){
            ans1[i+1]+=ans1[i]/10;ans1[i]%=10;
        }
    if(ans1[ans1[0]+1])ans1[0]++;
    while(ans1[ans1[0]]>9){
        ans1[ans1[0]+1]+=ans1[ans1[0]]/10;
        ans1[ans1[0]]%=10;ans1[0]++;
    }
    int k=1;
    for(int i=ans1[0];i>=1;i--)
        if(ans1[i]){
            k=i;break;
        }
    ans1[0]=k;
}
void mul2(int x){
    ans2[0]=money[0];
    for(int i=1;i<=ans2[0];i++)
        ans2[i]=money[i]*x;
    for(int i=1;i<=ans2[0];i++)
        if(ans2[i]>9){
            ans2[i+1]+=ans2[i]/10;ans2[i]%=10;
        }
    if(ans2[ans2[0]+1])ans2[0]++;
    while(ans2[ans2[0]]>9){
        ans2[ans2[0]+1]+=ans2[ans2[0]]/10;
        ans2[ans2[0]]%=10;ans2[0]++;
    }
    int k=1;
    for(int i=ans2[0];i>=1;i--)
        if(ans2[i]){
            k=i;break;
        }
    ans2[0]=k;
}
int main()
{
    n=init();m=init();t=init();scanf("%s",s);
    int len=strlen(s);
    for(int i=len-1;i>=0;i--)
        if(s[i]>='0'&&s[i]<='9')
            money[++money[0]]=s[i]-'0';
    for(int i=1;i<=n;i++){
        scanf("%d",&W[i]);
        if(W[i]>t)cnt++;
    }
    for(int i=1;i<=m;i++)
        for(int l=1;l<=n;l++)
            for(int r=l;r<=n;r++){
                for(int k=0;k<=t;k++)dp[k]=0;
                for(int k=l;k<=r;k++)
                    for(int w=t;w>=W[k];w--)
                        dp[w]=max(dp[w],dp[w-W[k]]+1);
                f[i][r][t]=max(f[i][r][t],f[i-1][l-1][t]+dp[t]);
            }
    mul1(f[m][n][t]);mul2(n-cnt-f[m][n][t]);
    for(int i=ans1[0];i>=1;i--)printf("%d",ans1[i]);printf(" ");
    for(int i=ans2[0];i>=1;i--)printf("%d",ans2[i]);
    return 0;
}

最大正方形子矩阵 开始还wa了QAQ

/* codevs 1773 空间有点挤 猥琐的打short2333*/
#include<iostream>
#include<cstdio>
#define maxn 2510
using namespace std;
short n,m,l[maxn][maxn],r[maxn][maxn],p[maxn][maxn],f[maxn][maxn],s[maxn][maxn],g[maxn][maxn],ans;
short init(){
    short x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
int main()
{
    n=init();m=init();
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            g[i][j]=init();
            if(g[i][j])f[i][j]=s[i][j]=1;
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(g[i-1][j]==0&&i>1)
                p[i][j]=p[i-1][j]+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            if(g[i][j-1]==0&&j>1)
                l[i][j]=l[i][j-1]+1;
    for(int i=1;i<=n;i++)
        for(int j=m;j>=1;j--)
            if(g[i][j+1]==0&&j<m)
                r[i][j]=r[i][j+1]+1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(g[i][j]&&g[i-1][j-1])//min min min  
                f[i][j]=min(f[i-1][j-1],min(l[i][j],p[i][j]))+1;
            ans=max(ans,f[i][j]);
        }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++){
            if(g[i][j]&&g[i-1][j+1])
                s[i][j]=min(s[i-1][j+1],min(p[i][j],r[i][j]))+1;
            ans=max(ans,s[i][j]);
        }
    cout<<ans<<endl;
    return 0;
}

多维LIS问题

/*codevs 1256 暴力n*n*m..... 20*/
#include<cstdio>
#define maxn 110
using namespace std;
int n,m,f[2][maxn][maxn],c[maxn],T,ans;
short G[1010][maxn][maxn];
int init(){
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
int max(int x,int y){
    return x>y?x:y;
}
int main()
{
    freopen("mouse.in","r",stdin);
    freopen("mouse.out","w",stdout);
    n=init();m=init();
    int x,y,t;
    for(int i=1;i<=m;i++){
        t=init();x=init();y=init();
        G[t][x][y]++;T=max(T,t);
    }
    for(int i=1;i<=T;i++){
        for(int j=1;j<=n;j++)    
            for(int k=1;k<=n;k++){
                f[i&1][j][k]=f[i-1&1][j][k];
                if(j>1)f[i&1][j][k]=max(f[i&1][j][k],f[i-1&1][j-1][k]+G[i][j][k]);
                if(k>1)f[i&1][j][k]=max(f[i&1][j][k],f[i-1&1][j][k-1]+G[i][j][k]);
                if(j<n)f[i&1][j][k]=max(f[i&1][j][k],f[i-1&1][j+1][k]+G[i][j][k]);
                if(k<n)f[i&1][j][k]=max(f[i&1][j][k],f[i-1&1][j][k+1]+G[i][j][k]);
                ans=max(ans,f[i&1][j][k]);
            }
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n;k++)
                f[i-1&1][j][k]=0;
    }    
    printf("%d
",ans);
    return 0;
} 
/* codevs 1256 这有点打脸啊...多维LIS问题居然没看出来 还是太弱...*/
#include<cstdio>
#define maxn 10010
using namespace std;
int n,m,f[maxn],x[maxn],y[maxn],t[maxn],ans;
int init(){
    int x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
int max(int x,int y){
    return x>y?x:y;
}
int Abs(int x){
    return x>0?x:-x;
}
int main()
{
    freopen("mouse.in","r",stdin);
    freopen("mouse.out","w",stdout);
    n=init();m=init();
    for(int i=1;i<=m;i++){
        t[i]=init();x[i]=init();y[i]=init();
    }
    for(int i=1;i<=m;i++){
        for(int j=1;j<i;j++)
            if(Abs(x[i]-x[j])+Abs(y[i]-y[j])<=t[i]-t[j])
                f[i]=max(f[i],f[j]+1);
        ans=max(ans,f[i]);
    }    
    printf("%d
",ans+1);
    return 0;
}

 单调队列优化dp

/*codevs 3327 dp+单调队列优化 */
#include<iostream>
#include<cstdio>
#define maxn 100010
#define ll long long
using namespace std;
int n,k,q[maxn],head,tail;
ll f[maxn],s[maxn],x,ans;
ll init(){
    ll x=0,f=1;char s=getchar();
    while(s<'0'||s>'9'){if(s=='0')f=-1;s=getchar();}
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x*f;
}
ll max(ll x,ll y){
    return x>y?x:y;
}
void Insert(int x){
    ll mx=f[x-1]-s[x];
    while(head<=tail&&f[q[tail]-1]-s[q[tail]]<mx)tail--;
    q[++tail]=x;
}
int main()
{
    n=init();k=init();
    for(int i=1;i<=n;i++){
        x=init();s[i]=s[i-1]+x;
    }
    Insert(1);
    for(int i=1;i<=n;i++){
        if(i-q[head]>k)head++;
        f[i]=f[q[head]-1]-s[q[head]]+s[i];
        Insert(i+1);ans=max(ans,f[i]);
    }
    cout<<ans<<endl;
    return 0;
}

 传说中的棋盘dp三水

/*codevs 2853 n*n*n*n 卡过*/
#include<cstdio>
#define maxn 110
using namespace std;
int n,g[maxn][maxn],f[2][maxn][maxn][maxn];
int Abs(int x){
    return x>0?x:-x;
}
int max(int x,int y){
    return x>y?x:y;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&g[i][j]);
    for(int x1=1;x1<=n;x1++){
        for(int y1=1;y1<=n;y1++)
            for(int x2=1;x2<=n;x2++)
                for(int y2=1;y2<=n;y2++){
                    f[x1&1][y1][x2][y2]=max(f

[x1&1][y1][x2][y2],f[x1-1&1][y1][x2-1][y2]+Abs(g[x1][y1]-g[x2][y2]));
                    f[x1&1][y1][x2][y2]=max(f

[x1&1][y1][x2][y2],f[x1-1&1][y1][x2][y2-1]+Abs(g[x1][y1]-g[x2][y2]));
                    f[x1&1][y1][x2][y2]=max(f

[x1&1][y1][x2][y2],f[x1&1][y1-1][x2-1][y2]+Abs(g[x1][y1]-g[x2][y2]));
                    f[x1&1][y1][x2][y2]=max(f

[x1&1][y1][x2][y2],f[x1&1][y1-1][x2][y2-1]+Abs(g[x1][y1]-g[x2][y2]));
                }
        for(int y1=1;y1<=n;y1++)
            for(int x2=1;x2<=n;x2++)
                for(int y2=1;y2<=n;y2++)
                    f[x1-1&1][y1][x2][y2]=0;
    }
    printf("%d
",f[n&1][n][n][n]);
    return 0;        
}
/*codevs 2853 优化 f[i][j][k] Ax=i By=j k步 那么左边可以表示了就 Orz */
#include<cstdio>
#define maxn 210
using namespace std;
int n,g[maxn][maxn],f[maxn][maxn][maxn*2];
int Abs(int x){
    return x>0?x:-x;
}
int max(int x,int y){
    return x>y?x:y;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            scanf("%d",&g[i][j]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
            for(int k=1;k<=n*2-1;k++)if(k>j-1&&k>i-1){
                f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k-1]+Abs(g[i][k-i+1]-g[k-j+1][j]));
                f[i][j][k]=max(f[i][j][k],f[i-1][j][k-1]+Abs(g[i][k-i+1]-g[k-j+1][j]));
                f[i][j][k]=max(f[i][j][k],f[i][j-1][k-1]+Abs(g[i][k-i+1]-g[k-j+1][j]));
                f[i][j][k]=max(f[i][j][k],f[i][j][k-1]+Abs(g[i][k-i+1]-g[k-j+1][j]));
            }
    printf("%d
",f[n][n][2*n-1]);
    return 0;        
}

然后是线段覆盖类型 无聊打的nlogn优化

/*codevs 3095 */
#include<iostream>
#include<cstdio>
#include<algorithm>
#define maxn 1000010
#define ll long long
using namespace std;
ll n,m,f[maxn],c[maxn],num,ans;
struct node{
    ll l,r;
    ll v;
}p[maxn];
ll cmp(const node &x,const node &y){
    return (x.r==y.r&&x.l<y.l)||x.r<y.r;
}
ll init(){
    ll x=0;char s=getchar();
    while(s<'0'||s>'9')s=getchar();
    while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
    return x;
}
int main()
{
    m=init();
    for(int i=1;i<=m;i++){
        p[i].l=init();p[i].r=init();
        p[i].v=init();c[i]=p[i].r;
    }
    sort(p+1,p+1+m,cmp);sort(c+1,c+1+m);
    for(int i=1;i<=m;i++){
        ll pos=upper_bound(c+1,c+1+m,p[i].l)-c-1;
        f[i]=max(f[i-1],f[pos]+p[i].v);
        ans=max(ans,f[i]);
    }
    cout<<ans<<endl;
    return 0;
}
原文地址:https://www.cnblogs.com/yanlifneg/p/5981808.html