程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> POJ 1952 BUY LOW, BUY LOWER

POJ 1952 BUY LOW, BUY LOWER

編輯:C++入門知識

題意:求最長單調遞減子序列的長度以及有多少種途徑到達該最長單調遞減子序列。
思路:求最長單調遞減子序列是比較容易的了,關鍵是求路徑的條數。而且還要去重。如5 5 2 2 1,其實是只有一條5 2 1。該題難點就在於去重,去重方法如下:
我們在求單調遞減子序列的時候,可以用一個二重for循環求,在循環中dp[i]表示的是到第i個數時的單調遞減子序列的最長長度,我們用如下的for循環求遞減子序列的長度:
[cpp] 
for(int j = 0;j < i;++j){ 
              if(num[i] < num[j]){ 
                if(dp[j] > mmax) 
                    mmax = dp[j]; 
              } 
          } 
我們設數組cnt[i]表示有幾種途徑到達第i個數字時的最長長度。則cnt[i]的取值決定於cnt[j](num[j] > num[i] 且 dp[j] == dp[i] - 1 且 j < i),由於要去重,所以需要倒著循環,這是個比較難想的地方。我就在這裡卡了一天。。。。可以用下面的代碼實現:
[cpp] view plaincopy
CLR(flag,false); 
          for(int j = i-1;j >= 0 ;--j){ 
              if(num[i] < num[j] ){ 
                if(dp[j] == mmax && !flag[num[j]]){ 
                    flag[num[j]] = true; 
                    cnt[i] += cnt[j]; 
                } 
              } 
          } 
其中的flag數組就是去重的功能,即如果是兩個相同的數都能到達num[i],則計算一個就可以,且從後計算。
附幾組數據:
5
20 18 25 18 17
輸出:3 2
4
20 15 10 10
輸出:3 1
9
100 96 30  200 196 30  300 296 30
輸出:3 3
5
5 5 2 2 1
輸出:3 1       www.2cto.com
這幾種情況如果都考慮了的話,基本就對了。
代碼:
[cpp] 
#include <iostream> 
#include <string.h> 
#include<cstdio> 
using namespace std; 
 
#define CLR(arr,val) memset(arr,val,sizeof(arr)) 
const int N = 5010; 
int dp[N],num[N],sum[N]; 
bool flag[10*N]; 
long long cnt[N]; 
int main(){ 
    //freopen("1.txt","r",stdin); 
    int n; 
    while(scanf("%d",&n) != EOF){ 
      for(int i = 0;i < n;++i) 
          scanf("%d",&num[i]); 
      CLR(dp,0);      
      CLR(cnt,0); 
      CLR(flag,false); 
      dp[0] = 1;cnt[0]=1; 
      int mmax = 0; 
      for(int i = 1;i < n;++i){ 
          mmax = 0; 
          for(int j = 0;j < i;++j){ 
              if(num[i] < num[j]){ 
                if(dp[j] > mmax) 
                    mmax = dp[j]; 
              } 
          } 
          CLR(flag,false); 
          for(int j = i-1;j >= 0 ;--j){ 
              if(num[i] < num[j] ){ 
                if(dp[j] == mmax && !flag[num[j]]){ 
                    flag[num[j]] = true; 
                    cnt[i] += cnt[j]; 
                } 
              } 
          } 
          if(cnt[i] == 0)cnt[i] = 1; 
          dp[i] = mmax+1; 
      } 
      mmax = 0; 
      for(int i = 0;i < n;++i){ 
        if(mmax < dp[i]) 
            mmax = dp[i]; 
      } 
      long long ans = 0; 
      CLR(flag,false); 
      for(int i = n-1;i >= 0;--i){ 
        if(dp[i] == mmax) { 
            if(!flag[num[i]]){ 
               ans += cnt[i]; 
               flag[num[i]] = true; 
            } 
        } 
      } 
      printf("%d %lld\n",mmax,ans); 
    } 
    return 0; 

話說這道題卡了一天多啊,,
10417832 ac_Bool 1952 Wrong Answer     C++ 739B 2012-07-10 19:30:37
10429494 ac_Bool 1952 Accepted 296K 125MS C++ 1215B 2012-07-12 08:53:09 wa了8次。。。。


作者:wmn_wmn

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved