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
  • 相关阅读:
    417 Pacific Atlantic Water Flow 太平洋大西洋水流
    416 Partition Equal Subset Sum 分割相同子集和
    415 Add Strings 字符串相加
    414 Third Maximum Number 第三大的数
    413 Arithmetic Slices 等差数列划分
    412 Fizz Buzz
    410 Split Array Largest Sum 分割数组的最大值
    409 Longest Palindrome 最长回文串
    day22 collection 模块 (顺便对比queue也学习了一下队列)
    day21 计算器作业
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/7647510.html
Copyright © 2011-2022 走看看