zoukankan      html  css  js  c++  java
  • 【经典dp】 poj 3671

    开一个dp[30010][3]的数组

    其中dp[i][j]表示把第i个数改成j最少要花多少次

    那么状态转移方程就列出来了:

    令a=1 j!=a[i]

    0 j==a[i]

    那么dp[i][1]=dp[i-1][1]+a;

    dp[i][2]=min(dp[i-1][1],dp[i-1][2])+a;

    那么根据空间优化原理,我们的第一维的i不过是为了递推,那么可以优化掉。

    不过要注意的是,dp【2】的状态要先求,否则测试数据会是3,因为沿用了本次的dp【1】,而非上次的dp【1】。

    #include <iostream>
    #include <cstdio>
    #include <iostream>
    #include <cstdio>
    #include <memory.h>
    using namespace std;
    const int maxn=30002;
    //int dp[maxn][3];
    int dp[maxn];
    int cow[maxn];
    int main()
    {
       // freopen("in.txt","r",stdin);
        int n;
        cin >> n;
        for(int i=1;i<=n;i++)
        {
            cin >> cow[i];
            int flag;
            if(cow[i]==2)
            flag=0;
            else flag=1;
            //dp[i][2]=min(dp[i-1][1],dp[i-1][2])+flag;
            dp[2]=min(dp[1],dp[2])+flag;
             if(flag==0)flag=1;
            else flag=0;
           // dp[i][1]=dp[i-1][1]+flag;
            dp[1]=dp[1]+flag;
        }
         //cout << min(dp[n][1],dp[n][2])<< endl;
        cout << min(dp[1],dp[2])<< endl;
        return 0;
    }
    左右遍历,计算left【i】+right【i】的max:
    #include <iostream>
    #include <cstdio>
    #include <iostream>
    #include <cstdio>
    #include <memory.h>
    using namespace std;
    #define maxn 30002
    int s[maxn],l[maxn],r[maxn];
    int main()
    {
        //freopen("in.txt","r",stdin);
        memset(s,0,sizeof(s));
        memset(l,0,sizeof(l));
        memset(r,0,sizeof(r));
        int n;
        cin >> n;
        for(int i=1;i<=n;++i)
        {
            cin >> s[i];
        }
        if(s[1]==1)
        {
            l[1]=1;
        }
        for(int i=2;i<=n;i++)
        {
            if(s[i]==1)
            {
                l[i]=l[i-1]+1;
            }
            else l[i]=l[i-1];
        }
        if(s[n]==2)
        {
            r[n]=1;
        }
        for(int i=n-1;i>=0;i--)
        {
            if(s[i]==2)
            {
                r[i]=r[i+1]+1;
            }
            else r[i]=r[i+1];
        }
        int max=0;
        for(int i=1;i<=n;i++)
        {
            if(l[i]+r[i]>max)
            {
                max=l[i]+r[i];
            }
        }
        cout << n-max << endl;
        return 0;
    }
    还有一个不错的方法,我们先计算1的个数,然后从前遍历,每次判断:是2就自加1,不是就自减1,其中保存min,则为结果。实际上也为dp,每次的i值代表,编号为i的数组前面不可更改的数字1个数。 
    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int MAX=30000+10;
    int a[MAX]; //存储输入的串
    int main()
    {
        //freopen("in.txt","r",stdin);
        int cnt; //数组元素的个数
        int i; int min; //最少要改变的次数
        scanf("%d",&cnt);
        int num1=0;
        for (i=0;i<cnt;i++)
        {
            scanf("%d",&a[i]);
            if (a[i] == 1)
             num1++;
        } min=num1;
        for (i=0;i<cnt;i++)
        {
            (a[i] == 1) ? num1-- : num1++;  
            if (min > num1)  min = num1;
        }
        printf("%d
    ",min);
        return 0;
    }
    
    
  • 相关阅读:
    新男人八题---AStringGame
    hihocoder1457
    SPOJ
    后缀自动机
    牛客练习赛13D
    Educational Codeforces Round 38
    Binary Differences
    laravel 带条件的分页查询
    url添加时间戳
    安卓无法上传照片
  • 原文地址:https://www.cnblogs.com/balfish/p/4015218.html
Copyright © 2011-2022 走看看