zoukankan      html  css  js  c++  java
  • DP小合集

    1.Uva1625颜色的长度

    dp[i][j]表示前一个串选到第i个 后一个串选到第j个 的最小价值

    记一下还有多少个没有结束即dp2

    记一下每个数开始和结束的位置

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    char s1[5100],s2[5100];
    int fp[30],fq[30],ep[30],eq[30];
    const int INF=2147483233;
    int dp1[2][5100],dp2[2][5100];
    int main()
    {
        //freopen("color.in","r",stdin);
        //freopen("color.out","w",stdout);
        //写了个意义不明的滚动数组。。。
        //BGM:Hop
        scanf("%s%s",s1+1,s2+1);
        int n=strlen(s1+1),m=strlen(s2+1);
        for(int i=1;i<=n;i++)s1[i]-='A';
        for(int i=1;i<=m;i++)s2[i]-='A';
        for(int i=0;i<26;i++)fp[i]=fq[i]=INF;
        for(int i=1;i<=n;i++)
        {
            fp[s1[i]]=min(fp[s1[i]],i);  
            ep[s1[i]]=i;  
        }
        for(int i=1;i<=m;i++)
        {
            fq[s2[i]]=min(fq[s2[i]],i);  
            eq[s2[i]]=i;  
        }
        int cur=0;
        for(int i=0;i<=n+1;i++)
        {
            for(int j=0;j<=m+1;j++)
            {
                if(!i && !j)continue;
                int v1=INF,v2=INF;  
                if(i)v1=dp1[cur^1][j]+dp2[cur^1][j]; 
                if(j)v2=dp1[cur][j-1]+dp2[cur][j-1];
                dp1[cur][j]=min(v1,v2);
                if(i)     
                {  
                    dp2[cur][j]=dp2[cur^1][j];  
                    if(fp[s1[i]]==i&&fq[s1[i]]>j)dp2[cur][j]++;  
                    if(ep[s1[i]]==i&&eq[s1[i]]<=j)dp2[cur][j]--;  
                }  
                else if(j)  
                {  
                    dp2[cur][j]=dp2[cur][j-1];  
                    if(fq[s2[j]]==j&&fp[s2[j]]>i)dp2[cur][j]++;  
                    if(eq[s2[j]]==j&&ep[s2[j]]<=i)dp2[cur][j]--;  
                }  
            }
            cur=cur^1;
        }
        cout<<dp1[cur^1][m];
        return 0;
    }
    意义不明的滚动数组

    2.Uva12563劲歌金曲

    首先留出1s来唱最后一首歌

    剩下的简单的背包+记录路径

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    const int MAXN=110000;
    int n,T;
    int a[MAXN];
    int w[55];
    int b[MAXN];
    int main()
    {
        freopen("party.in","r",stdin);
        freopen("party.out","w",stdout);
        cin>>n>>T;
        for(int i=0;i<n;i++)cin>>w[i];
        T=min(T,100010);
        T--;//长者续命-1s 苟利国家生死以岂因祸福避趋之 敢同恶鬼争高下,不向霸王让寸分
        //你们啊Naive!你们有一个好 全世界到哪个地方你们比其他的西方记者跑的还快
        //美国的华莱士不知比你们高到哪里去了我跟他谈笑风生 
        sort(w,w+n);
        for(int i=0;i<n;i++)
            for(int j=T;j>=w[i];j--)
                if((b[j]<b[a[j-w[i]]]+1) || (b[j]==b[a[j-w[i]]]+1 && a[j]<a[j-w[i]]+w[i]) )
                {
                    a[j]=a[j-w[i]]+w[i];
                    b[j]=b[a[j-w[i]]]+1;
                }
        b[T]++;
        cout<<b[T]<<" "<<a[T]+678;
        return 0;
    }
    -1s很重要

    3.回文子串

    把一个字符串切成若干回文子串 问最少切多少个

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    const int MAXN=1010;
    const int INF=2147483233;
    int dp[MAXN];
    char s[MAXN];
    bool judge(int i,int j)
    {
        while(i<j)if(s[i++]!=s[j--])return false;
        return true;
    }
    int main()
    {
        freopen("string.in","r",stdin);
        freopen("string.out","w",stdout);
        scanf("%s",s+1);
        dp[0]=0;
        int len=strlen(s+1);
        for(int i=1;i<=len;i++)dp[i]=INF;
    
        for(int i=1;i<=len;i++)
            for(int j=1;j<=i;j++)
                if(judge(j,i))dp[i]=min(dp[i],dp[j-1]+1);
        
        printf("%d
    ",dp[len]);
        
        return 0;
    }
    直接上代码吧= =

    4.切木棍

    有一个长为L的棍子,还有n个切割点的位置(按从小到大排列)。你的任务是在这些切割点的位置处把棍子切成n+1部分,使得总切割的费用最少。每次切割的费用等于被切割的木棍长度。

    区间dp

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    int l,n;
    const int inf=2147483233;
    int dp[150][150];
    int a[150];
    int main()
    {
        freopen("stick.in","r",stdin);
        freopen("stick.out","w",stdout);
        scanf("%d%d",&l,&n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]);a[0]=0;a[n+1]=l;
        sort(a+1,a+n+1);
        for(int len=2;len<=n+1;len++)
            for(int i=0;i<=n+1-len;i++)
            {
                dp[len][i]=inf;
                for(int j=1;j<=len-1;j++)dp[len][i]=min(dp[len][i],dp[j][i]+dp[len-j][i+j]+a[len+i]-a[i]);
            }
        cout<<dp[n+1][0];
    }
    似乎发过的= =

    5.走过去再走回来

    给定平面上n个点(横坐标严格递增)你要从最左边走到最右边再走回来 走欧几里得距离 而且要求每个点都走到 求走的最短路

    一开始到洗手间数学证明了半天。。。后来发现还是鸡神设计的状态好(Orz Jackyyc)

    dp[i][j]表示前面的人走到i 后面的人走到j 且1~i每个点都走过了

    然后记忆化搜索嗖嗖嗖就出来了

    再次Orz Jackyyc

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    inline int read()
    {
        char ch=getchar();
        int x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
        return x*f;
    }
    const double eps=1e-4;
    struct point
    {
        double x,y;
    }p[1010];
    double d(point a,point b)
    {
        double ans=sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
        return ans;
    }
    int n;
    double dp[1010][1010];
    double dis[1010][1010];
    double Dp(int a,int b)
    {
        if(dp[a][b])return dp[a][b];
        else return dp[a][b]=min(Dp(a+1,b)+dis[a][a+1],Dp(a+1,a)+dis[b][a+1]);
    }
    int ans=2147483647.0;
    int main()
    {
        freopen("route.in","r",stdin);
        freopen("route.out","w",stdout);
        n=read();
        for(int i=1;i<=n;i++)scanf("%lf%lf",&p[i].x,&p[i].y);
        for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)dis[i][j]=d(p[i],p[j]);
        for(int i=1;i<n-1;i++)dp[n-1][i]=dis[n-1][n]+dis[i][n];
        double ans=Dp(1,1);
        
        printf("%.2lf",ans);
        return 0;
    }
    View Code

    6.城市里的间谍uva1025
    预处理比较烦

    judge[t][i][0]表示在时间t 车站i 有一个向左开的车

    judge[t][i][1]表示在时间t 车站i 有一个向右开的车

    对于每个时间 有三个决策 不动 朝左 朝右

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        char ch=getchar();
        int x=0,f=1;
        while(!isdigit(ch)){if(ch=='-')f=-f;ch=getchar();}
        while(isdigit(ch)){x=10*x+ch-'0';ch=getchar();}
        return x*f;
    }
    const int INF=2147483233;
    int n,m,T,M;
    const int maxn=300;
    int t[maxn],d[maxn],D[maxn];
    bool judge[maxn][maxn][2];
    int dp[maxn][maxn];
    int main()
    {
        freopen("spy.in","r",stdin);
        freopen("spy.out","w",stdout);
        scanf("%d%d",&n,&T);
        for(int i=1;i<=n-1;i++)scanf("%d",&t[i]);
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%d",&d[i]);
            int te=d[i];
            if(d[i]<T)judge[d[i]][1][1]=1;
            for(int j=1;j<=n-1;j++)
            {
                if(te+t[j]<=T)
                {
                    judge[te+t[j]][j+1][1]=1;
                    te=te+t[j];
                }
                else break;
            }
        }
        scanf("%d",&M);
        for(int i=1;i<=M;i++)
        {
            scanf("%d",&D[i]);
            int te=D[i];
            if(D[i]<T)judge[D[i]][n][0]=1;
            for(int j=n-1;j>=1;j--)
            {
                if(te+t[j]<=T)
                {
                    judge[te+t[j]][j][0]=1;
                    te=te+t[j];
                }
                else break;
            }
        }
        for(int i=1;i<=n-1;i++)dp[T][i]=INF;
        dp[T][0]=0;
        for(int i=T-1;i>=0;i--)
        {
            for(int j=1;j<=n;j++)
            {
                dp[i][j]=dp[i+1][j]+1;
                if(j<n && judge[i][j][1] && i+t[j]<=T)dp[i][j]=min(dp[i][j],dp[i+t[j]][j+1]);
                if(j>1 && judge[i][j][0] && i+t[j-1]<=T)dp[i][j]=min(dp[i][j],dp[i+t[j-1]][j-1]);
            }
        }
        if(dp[0][1]>=INF)cout<<"impossible";
        else cout<<dp[0][1];
    }
    View Code
  • 相关阅读:
    Linux应用程序的地址布局
    C/C++中的内存四区!
    编程语言的选择重不重要?对普通人而言,反其道而行更可靠!
    【C语言程序设计】C语言求最大公约数(详解版)!
    【C语言程序设计】C语言求最小公倍数(详解版)!
    【C语言程序设计】C语言求定积分!腻不腻害!
    你是因为什么而当程序员啊!网友们众说纷纭,从装b到被逼,理由层出不穷!
    华为程序员爆料:主动离职,公司竟也给n+1,到手15万,华为真良心!
    【C语言程序设计】C语言整数逆序输出程序!
    copy 和 mutablecopy
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/7647510.html
Copyright © 2011-2022 走看看