简单DP-艰难取舍

艰难取舍(seq.cpp/c/pas)

【题目描述】

由于hyf长得实在是太帅了,英俊潇洒,风流倜傥,人见人爱,花见花开,车见车载。有一群MM排队看hyf。每个 MM都有自己独特的风格,由于 hyf有着一颗包容的心,所以,什么风格的MM他都喜欢……

但是,hyf有一个特别的要求,他不希望总是看到风格得差不多的 MM,更加特别的是,如果两个MM风格完全一样,hyf不会有任何意见。

现在,hyf希望从去看他的 MM中,去掉一些MM,从而使得相邻2个 MM的风格值的差(绝对值)不为1。自然地,hyf希望去掉的MM越少越好。

【输入格式】

第一行一个整数N;

第 2~N+1行N 个整数,第i个为 ci。表示第i个MM的风格值。

【输出格式】

一个数,表示最少要去掉的 MM数。

【样例输入1】

6

4

2

2

1

1

1

【样例输出1】

2

【数据范围】

对于30%的数据,N≤20

对于70%的数据,N≤100,ci ≤ 2000

对于100%的数据,N≤1000   0 ≤ ci ≤ 2000

  这道题可以用动态规划的算法来解决。

  用数组F[i]来表示从第1个到第i个数最多可以留下几个。

  那么显然F[i]可以由F[j](1<=j<=i-1)加1推得。即当前最优情况下与第i个数相邻的是第j个数,并且这里的j要满足i和j的差绝对值不为1。则F[i]=max{F[j]}+1,且|a[i]-a[j]|<>1。这个算法的时间复杂度为O(n^2)。

  另外,可以发现a[j]与a[i]不能相邻的情况只有a[j]=a[i]+1和a[j]=a[i]-1。所以,不需穷举1到i-1,只需找出1到i-1中最大的3个F[j]即可,其中必须确保F[j]不彼此相等,这样满足条件的max{F[j]}必然是在这3个F[j]中,这样就可将算法的时间复杂度缩小到O(3N)。

  这道题也可以用暴力枚举来实现,对于一个序列a1,a2,a3…an,可以]用一个数组b[a[i]]来记录到达a[i]的最大存在个数。通过枚举存在2个,3个,4个…n个人时的最大值来取得。

  例:一开始只存在a1和a2,a3…an中的任意一个时的最大值放在b[a[i]]中,然后再搜索只存在3个人时a1,a2和a3,a4….an中的任意一个时的最大值,由于a1,a2两个人的最大值已存在b[a[2]]中了,所以只要寻找a2和a3,a4…an中任意一个的最大值即可,比较b[a[i]]是否大于b[a[2]]+1,并将结果放在b[a[i]]中。同理依次枚举至n个人为止。最后在b[1]…b[n]中找出最大值即可。

    for i:=1 to n do//枚举每次存在从a[1]开始的i个人

            for j:=i+1 to n do//更新前i个人和到第j个人之间的最大人数

               if (abs(c[j]-c[i])<>1) and (s[i]+1>s[j]) then s[j]:=s[i]+1;

AC_code:

var
        j,i,n,maxs:longint;
        c,f:array[1..1001] of longint;
function max(a,b:longint):longint;
begin
        if a>b then exit(a);
        exit(b);
end;
begin
assign(input,‘seq.in‘);
assign(output,‘seq.out‘);
reset(input);rewrite(output);
        readln(n);
        for i:=1 to n do readln(c[i]);
        for i:=1 to n do begin
                f[i]:=1;
                for j:=1 to i-1 do
                        if abs(c[j]-c[i])<>1 then f[i]:=max(f[i],f[j]+1);
        end;
        maxs:=-0;
        for i:=1 to n do if f[i]>maxs then maxs:=f[i];
        writeln(n-maxs);
close(input);close(output);
end.
时间: 2024-08-06 19:27:17

简单DP-艰难取舍的相关文章

POJ 3250 Bad Hair Day 简单DP 好题

Description Some of Farmer John's N cows (1 ≤ N ≤ 80,000) are having a bad hair day! Since each cow is self-conscious about her messy hairstyle, FJ wants to count the number of other cows that can see the top of other cows' heads. Each cow i has a sp

hdu1207 汉诺塔II 简单dp

本文出自:http://blog.csdn.net/svitter 题意:汉诺塔,多了一根柱子,问你寻找最快的移动次数. dp [ n ] = dp [ n - j ] * 2 + pow( 2, j ) - 1; 就是把j个汉诺塔移到一根上dp[ n - j ],然后就是普通的汉诺塔问题,即2^n - 1次移动, 然后把剩下的移动过去dp [ n - j ]. 注意pow(2, j )可能超出long long int范围.写二的次方的时候也可用移位算法. #include <iostream

POJ1088:滑雪(简单dp)

题目链接:  http://poj.org/problem?id=1088 题目要求: 一个人可以从某个点滑向上下左右相邻四个点之一,当且仅当高度减小.求可以滑落的最长长度. 题目解析: 首先要先排一下序,因为只能高度递减才能滑行.之后就很简单了,就是简单DP. 即:要求的滑坡是一条节点递减并依次相邻的最长路径,可以先根据高度将所有的点进行排序,在i点的时候,遍历0~i-1个点(升序排序,i前面的点的高度一定小于等于i),取相邻点间的大的路径长度 代码如下: #include <iostream

hdu 1087 简单dp

思路和2391一样的.. <span style="font-size:24px;">#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; const int inf=(0x7f7f7f7f); int main() { int a; int s[10005]; int w[10005];

hdu1087 简单DP

I - 简单dp 例题扩展 Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Description Nowadays, a kind of chess game called “Super Jumping! Jumping! Jumping!” is very popular in HD

2014 HDU多校弟九场I题 不会DP也能水出来的简单DP题

听了ZWK大大的思路,就立马1A了 思路是这样的: 算最小GPA的时候,首先每个科目分配到69分(不足的话直接输出GPA 2),然后FOR循环下来使REMAIN POINT减少,每个科目的上限加到100即可 算最大GPA的时候,首先每个科目分配到60分,然后FOR循环下来使REMAIN POINT减少,每个科目的上限加到85即可,如果还有REMAIN POINT,就FOR循环下来加到100上限即可 不会DP 阿 QAQ 过段时间得好好看DP了  =  = 于是默默的把这题标记为<水题集> //

Codeforces 41D Pawn 简单dp

题目链接:点击打开链接 给定n*m 的矩阵 常数k 下面一个n*m的矩阵,每个位置由 0-9的一个整数表示 问: 从最后一行开始向上走到第一行使得路径上的和 % (k+1) == 0 每个格子只能向或走一步 求:最大的路径和 最后一行的哪个位置作为起点 从下到上的路径 思路: 简单dp #include <cstdio> #include <algorithm> #include<iostream> #include<string.h> #include &

HDU 4826 简单DP

Problem Description 度度熊是一只喜欢探险的熊,一次偶然落进了一个m*n矩阵的迷宫,该迷宫只能从矩阵左上角第一个方格开始走,只有走到右上角的第一个格子才算走出迷宫,每一次只能走一格,且只能向上向下向右走以前没有走过的格子,每一个格子中都有一些金币(或正或负,有可能遇到强盗拦路抢劫,度度熊身上金币可以为负,需要给强盗写欠条),度度熊刚开始时身上金币数为0,问度度熊走出迷宫时候身上最多有多少金币? Input 输入的第一行是一个整数T(T < 200),表示共有T组数据.每组数据的

UVA - 11584 划分字符串的回文串子串; 简单dp

/** 链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=34398 UVA - 11584 划分字符串的回文串子串: 简单dp 题目大意: 给一个字符串, 要求把它分割成若干个子串,使得每个子串都是回文串.问最少可以分割成多少个. 定义:dp[i]表示前0~i内的字符串划分成的最小回文串个数: dp[i] = min(dp[j]+1 | j+1~i是回文串); 先预处理flag[i][j]表示以i~j内的字符串为回文串

poj 2193 Lenny&#39;s Lucky Lotto Lists 简单dp

//poj 2193 //sep9 #include <iostream> using namespace std; typedef __int64 INT; INT dp[16][2048]; int n,m; int main() { int cases,t=0; scanf("%d",&cases); while(cases--){ scanf("%d%d",&n,&m); memset(dp,0,sizeof(dp));