码迷,mamicode.com
首页 > 其他好文 > 详细

【经典dp】 poj 3671

时间:2014-10-10 12:25:34      阅读:122      评论:0      收藏:0      [点我收藏+]

标签:style   blog   color   io   os   for   数据   sp   div   

开一个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\n",min);
    return 0;
}

 

 

【经典dp】 poj 3671

标签:style   blog   color   io   os   for   数据   sp   div   

原文地址:http://www.cnblogs.com/balfish/p/4015218.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!