1. 程式人生 > >合唱隊問題的動態規劃解法

合唱隊問題的動態規劃解法

#include <stdlib.h>
#include "oj.h"
#include <iostream>
using namespace std;
int lASS(int *a,int n,bool(*pfun)(int,int),int* f)
{
 
 f[1]=1; //陣列f用來記錄從元素1開始截止到下表i的最長遞增子序列的長度

 //這裡f[1]必須初始化為
 for(int i=2;i<=n;i++)//自底向上增加問題的規模,則f[n]就儲存了從1到n的最長遞增子序列的長度
 {
  f[i]=1;// 先初始化一個比較小的值
  //for(int j=i-1;j>0;j--)//遍歷第i個元素前面的所有元素
  for(int j=1;j<i;j++)//遍歷第i個元素前面的所有元素
  {
   
       
     if(f[j]+1>f[i])//如果到下標j的最長遞增子序列長度+1比當前f[i]大 
     {
      if(pfun(a[j],a[i])) //如果a[j]<a[i]
           {
           f[i]=f[j]+1;//則截止到i的最長遞增子序列可增一
        
              }
      
      
        }
    
      
   
  }//for
  cout<<"f["<<i<<"]="<<f[i]<<endl;
  
 }
 int max=1;
 for(int i=1;i<=n;i++)
  if(max<f[i]) max=f[i];
 return max;
}//function

 

 


int lDSS(int *a,int n,bool(*pfun)(int,int),int* f)
{
 
 f[n]=1; //陣列f用來記錄從元素1開始截止到下表i的最長遞增子序列的長度
 //這裡f[1]必須初始化為
 for(int i=n-1;i>0;i--)//自底向上增加問題的規模,則f[n]就儲存了從1到n的最長遞增子序列的長度
 {
  f[i]=1;// 先初始化一個比較小的值
  //for(int j=i-1;j>0;j--)//遍歷第i個元素前面的所有元素
  for(int j=n;j>i;j--)//遍歷第i個元素前面的所有元素
  {
       
     if(f[j]+1>f[i])//如果到下標j的最長遞增子序列長度+1比當前f[i]大 
     {
      if(pfun(a[j],a[i])) //如果a[j]<a[i]
           {
           f[i]=f[j]+1;//則截止到i的最長遞增子序列可增一
              }   
      
        }
    
      
   
  }//for
  cout<<"f["<<i<<"]="<<f[i]<<endl;
 }
 int max=1;
 for(int i=1;i<=n;i++)
  if(max<f[i]) max=f[i];
 return max;
}//function


//#include "lASS.h"

/*
功能:計算最少出列多少位同學,使得剩下的同學排成合唱隊形
    
輸入引數:
  int N : 最初佇列的N位同學 (2<=N<=50)
  char* statureArray:N位同學的身高字串(保證只含數字和空格)
          身高Ti要求(130<=Ti<=230)
輸出引數: 
  int* rst: 最少出列多少位同學,使得剩下的同學排成合唱隊形
返回值:
  0: 成功; -1:異常 
*/
bool parseArray(char* Sa,int* a,int n)
{
  char* pstr=Sa;
  cout<<endl;
  for(int i=1;i<=n;i++)
  {
     a[i]=atoi(pstr);
  pstr+=4;
     cout<<"a["<<i<<"]"<<"is "<<a[i]<<endl;
  }
  return true;
  
}

int chorus(int N, char* StatureArray, int* Rst)
{
 int* a=new int[N+1];;
    parseArray(StatureArray,a,N);
 int* f1=new int[N+1];
 int* f2=new int[N+1];
    
    cout<<"the longest ascend sub sequence"<<lASS(a,N,st,f1)<<endl;
 
 cout<<"the  longest descend sub sequence"<<lDSS(a,N,st,f2)<<endl;

 if(f1[N]==N||f1[N]==N) return false;// 單調序列無法組成合唱隊
 
 int max=0;
 
 for(int i=1;i<=N;i++)
  if(max<f1[i]+f2[i]-1) max=f1[i]+f2[i]-1;
 *Rst=N-max;
 cout<<endl<<*Rst<<endl;
 
 
 return 0;
}




 

 


問題描述:

N位同學站成一排,音樂老師要請其中的(N-K)位同學出列,使得剩下的K位同學不交換位置就能排成合唱隊形。
合唱隊形是指這樣的一種隊形:設K位同學從左到右依次編號為1, 2, …, K,他們的身高分別為T1, T2, …, TK,
則他們的身高滿足T1 < T2 < … < Ti , Ti > Ti+1 > … > TK (1 <= i <= K)。
你的任務是,已知所有N位同學的身高,計算最少需要幾位同學出列,可以使得剩下的同學排成合唱隊形。


功能描述:計算最少出列多少位同學,使得剩下的同學排成合唱隊形
    
輸入引數:
     int N : 最初佇列的N位同學 (2<=N<=50)
     char* statureArray:N位同學的身高字串(保證只含數字和空格)
             身高Ti要求(130<=Ti<=230)
輸出引數:
     int* rst: 最少出列多少位同學,使得剩下的同學排成合唱隊形
返回值:
        0: 成功; -1:異常

分析:問題的關鍵在於同學的排列順序不能改變,這就降低了問題的複雜度,可以用動態規劃來求解。

這樣分析就是典型的最長下降子序列問題。只要列舉每一個人站中間時可以的到的最優解。顯然它就等於,包括他在內向左求最長上升子序列,向右求最長下降子序列。

其實最長子序列只要一次就可以了。因為最長下降(上升)子序列不受中間人的影響。

只要用OPT1求一次最長上升子序列,OPT2求一次最長下降子序列。這樣答案就是N-max<i>(opt1[i]+opt2[i]-1).

...........

思路:該題的關鍵是不能置換隊員的順序,這個要求降低了問題的難度,如果可以排列的話就難了,建一個堆總會出現重複的元素,如何調整還沒想出來怎麼做。

考慮不能排列的情況,先對整個佇列求一個最長遞增子序列再求一個最長遞降子序列。則剩下的人數就好算了。因為最長遞增子序列是一個典型的動態規劃問題,設子問題的解是

FAscend[i]FDescend[i]則合唱隊問題的最優解是N-max[i]{FAscend[i]+ FDescend[i]-1}

關鍵:最優子結構的性質,遞迴定義子問題的解,自底向上求解

一,     最長遞增子序列問題的描述設L=<a1,a2,…,an>是n個不同的實數的序列,L的遞增子序列是這樣一個子序列Lin=<aK1,ak2,…,akm>,其中k1<k2<…<kmaK1<ak2<…<akm。求最大的m值。

二,     最長遞增子序列問題的最優子結構性質:

設f(i)表示序列中以ai為末尾元素的最長遞增子序列的長度。在求以ai為末尾的最長遞增子序列時,找到所有序號在L前面且小於ai的元素aj,即j<I,且aj<ai。如果這樣的元素存在,那麼對於所有的aj,都有一個以aj為末尾元素的最長遞增子序列的長度,把其中最大的f(j)選出來,那麼f(i)就等於最大的f(j)+1

F(i)=max[j]{f(j)+1},即以ai為末尾元素的最長遞增子序列,等於以使f(j)最大的哪個aj為末尾元素的遞增子序列最末再加上ai;如果這樣的元素不存在,那麼ai自身構成一個長度為1的以ai為末尾元素的遞增子序列。

三, 實現:用f【】來儲存最優值,外層迴圈擴大問題規模,即陣列f的下表遞增,內層迴圈遍歷從i到1的子問題的最優質。

 implementation:


相關推薦

合唱隊問題的動態規劃解法

#include <stdlib.h> #include "oj.h" #include <iostream> using namespace std; int lASS(int *a,int n,bool(*pfun)(int,int),int*

LeetCode刷題Easy篇斐波那契數列問題(遞迴,尾遞迴,非遞迴和動態規劃解法

題目 斐波那契數列:  f(n)=f(n-1)+f(n-2)(n>2) f(0)=1;f(1)=1;  即有名的兔子繁衍問題  1 1 2 3 5 8 13 21 .... 我的解法 遞迴 public static int Recursion

最大子陣列問題的暴力解法,遞迴解法動態規劃解法和暴力-遞迴混合解法

#include <stdio.h> #include <stdlib.h> #include <time.h> #include <math.h> #define SIZE 5000 #define RANDOM_LIMI

Leetcode解題筆記 5.Longest Palindromic Substring [Medium] 動態規劃解法

解題思路 題目要求我們尋找長度最長的子字串,考慮到由於題目符合運用動態規劃的3個性質——最優化原理、無後效性、有重疊子問題,所以可以用動態規劃的方法。難點在於構造如何設定子問題,怎麼初始化,以及怎麼遍歷。 構建子問題: 設d[i][j]表示字串s從第i

NYOJ 613免費餡餅 動態規劃解法

讀題:一開始看題感到無從下筆,看到T給出範圍後想到老師說看到引數給範圍便想一想能不能建陣列來解決。而這時認真看一下題,每一秒落在一個位置x上 不正好可以建一個數組 a【11】【100000】來儲存嗎; 構思: 由第一組測試資料 6 5 1 4 1 6 1 7 2 7 2

零錢兌換問題——python動態規劃解法

問題:給定不同面額的硬幣(coins)和一個總金額(amount)。寫一個函式來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合方式能組成總金額,返回-1。示例 1:coins = [1, 2, 5], amount = 11return 3 (11 = 5

增強學習(三)----- MDP的動態規劃解法

  上一篇我們已經說到了,增強學習的目的就是求解馬爾可夫決策過程(MDP)的最優策略,使其在任意初始狀態下,都能獲得最大的Vπ值。(本文不考慮非馬爾可夫環境和不完全可觀測馬爾可夫決策過程(POMDP)中的增強學習)。 那麼如何求解最優策略呢?基本的解法有三種: 動態規劃法(dy

【leetcode】55. Jump Game 動態規劃解法

Given an array of non-negative integers, you are initially positioned at the first index of the array.Each element in the array represents your maximum jum

UVA 357 Let Me Count The Ways 動態規劃解法、母函式解法

After making a purchase at a large department store, Mel's change was 17 cents. He received 1 dime, 1 nickel, and 2 pennies. Later that day, he was shop

最長對稱子串(動態規劃解法)

5-12 最長對稱子串   (25分) 對給定的字串,本題要求你輸出最長對稱子串的長度。例如,給定Is PAT&TAP symmetric?,最長對稱子串為s PAT&TAP s,於是你應該輸出11。 輸入格式: 輸入在一行中給出長度不超過1000

編輯距離問題——python動態規劃解法

問題:給定兩個單詞 word1 和 word2,計算出將 word1 轉換成 word2 所使用的最少運算元 。你可以對一個單詞進行如下三種操作:插入一個字元刪除一個字元替換一個字元示例 1:輸入: word1 = "horse", word2 = "ros" 輸出: 3 解

Combination Sum IV中兩種JAVA動態規劃解法的不同

Given an integer array with all positive numbers and no duplicates, find the number of possible combinations that add up to

動態規劃 跳臺階問題的三種解法

for 發現 規劃 == you new 我們 tair bing You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb 1 o

LeetCode 926. 將字串翻轉到單調遞增 遞迴實現動態規劃 兩種解法

這個題做了一個多小時,考慮複雜了。 開始推動規沒有推出來,然後找到一個遞推關係:從左往右,如果是0,則不需要變動;如果是1,則有兩種選擇(1)將1變為0(2)將1後面的所有數字變為1,這兩種方法中的變動數字最小的方法就是最佳方法,然後依次遞推,很容易寫出遞迴程式。但是這裡面存

動態規劃-揹包問題(跳躍點解法

  對於 0-1 揹包問題,DP的解法很普遍。還有一種“跳躍點”的解法,該方法的提出,是根據揹包求解過程中的記錄表 v(i,j)的函式性特點而來的。(v(i,j)表記錄的是前 i 種物品,達到總重量 j 時的最大利益) 可以Dp 求解一下,然後列印一下表進行觀察,也可以根據這個

NOIP2004合唱隊列(提高組T3)————單調佇列,動態規劃(最長上升序列,最長下降序列)

題解:本題主要考查單調佇列,動態規劃(最長上升序列,最長下降序列)。這個序列是一箇中間高,兩頭底的序列,先解決從T1到Ti這一段單調遞增的序列,再解決Ti到TK這一段單調遞減的序列(注意數值的更新)。 程式碼如下: #include<iostream> #include<

連續子陣列最大和O(n)兩種解法:雙指標 動態規劃

題目描述 HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會後,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題很好解決。但是,如果向量中包含負數,是否應該包含某個負數,並期望旁邊的正數會彌補它呢?例如:{6,-3,-2,7

[LeetCode]動態規劃中股票問題的通用解法

動態規劃中股票問題的通用解法 有一類動態規劃的問題是給定一個股票價格序列,然後計算買賣股票所能獲得的最大收益,這類問題通常有很多變種,例如只允許交易一次,允許交易多次或者增收交易稅等。即問題的最大收益通常由交易的時間和允許的最大交易次數(每次交易指一次買與一次

動態規劃的一些題目及解法

1、假設有幾種硬幣,如1、3、5,並且數量無限。請找出能夠組成某個數目的找零所使用最少的硬幣數。  解法: #include<stdio.h> int sum=0; void Min(int n) { if(n<1) Sum+=0; else if(n==

HDU 2602 動態規劃+二維陣列、一維陣列兩解法(01揹包)

這道題就是簡單用二維陣列解決的時候,就是簡單的動態規劃,但是坑就坑在可能出現體積為0但是價值不為0的例子 一:二維陣列 下面是錯誤的程式碼 #include <iostream> #include <cstring> #include <