您的位置:首页 > 其它

(复习)poj 1952 最长下降子序列—— dp+方案个数

2014-09-17 16:34 381 查看
BUY LOW, BUY LOWER

Time Limit: 1000MSMemory Limit: 30000K
Total Submissions: 8466Accepted: 2930
Description

The advice to "buy low" is half the formula to success in the bovine stock market.To be considered a great investor you must also follow this problems' advice:

"Buy low; buy lower"


Each time you buy a stock, you must purchase it at a lower price than the previous time you bought it. The more times you buy at a lower price than before, the better! Your goal is to see how many times you can continue purchasing at ever lower prices.

You will be given the daily selling prices of a stock (positive 16-bit integers) over a period of time. You can choose to buy stock on any of the days. Each time you choose to buy, the price must be strictly lower than the previous time you bought stock. Write
a program which identifies which days you should buy stock in order to maximize the number of times you buy.

Here is a list of stock prices:

Day   1  2  3  4  5  6  7  8  9 10 11 12

Price 68 69 54 64 68 64 70 67 78 62 98 87


The best investor (by this problem, anyway) can buy at most four times if each purchase is lower then the previous purchase. One four day sequence (there might be others) of acceptable buys is:

Day    2  5  6 10

Price 69 68 64 62


Input

* Line 1: N (1 <= N <= 5000), the number of days for which stock prices are given

* Lines 2..etc: A series of N space-separated integers, ten per line except the final line which might have fewer integers.

Output

Two integers on a single line:

* The length of the longest sequence of decreasing prices

* The number of sequences that have this length (guaranteed to fit in 31 bits)

In counting the number of solutions, two potential solutions are considered the same (and would only count as one solution) if they repeat the same string of decreasing prices, that is, if they "look the same" when the successive prices are compared. Thus,
two different sequence of "buy" days could produce the same string of decreasing prices and be counted as only a single solution.

Sample Input
12
68 69 54 64 68 64 70 67 78 62
98 87

Sample Output
4 2


本道题的最大收获就是知道了——

求解不重复的方案个数其实不一定需要对整个路径进行还原一一比较,在某些情况下可以一边dp一边排除

题目大意:

RT

思路&反省:

这道题是dp求解LIS的升级版,多了一个求解方案个数的提问。

(1)一开始还想着用一个配合着dp的同等大小的 set<string> 数组来去重求解,爆空间了无疑

下面是代码

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#define maxn 5005

using namespace std;
int a[maxn];
int dp[maxn];

int main()
{
int n;
while(scanf("%d",&n)!=EOF){
set<string> G[maxn];
for(int i=0;i<n;i+=1){
scanf("%d",&a[i]);
dp[i]=1;
char c[10];
sprintf(c, "%d", a[i]);
string news(c);
G[i].insert(news);
}

int res=0;
for(int i=0;i<n;i+=1){
int maxx=0;
for(int j=0;j<i;j+=1){
if(a[j]>a[i]&&dp[j]+1>dp[i]){
dp[i]=dp[j]+1;
maxx=max(maxx,dp[j]);

}
}
for(int j=0;j<i;j+=1){
if(a[j]>a[i]&&dp[j]==maxx){
for(set<string>::iterator k=G[j].begin();k!=G[j].end();k++){
string s;
s=(*k);
char c[10];
sprintf(c, "%d", a[i]);
string news(c);
s+=news;
G[i].insert(s);
}
}
}
res=max(res,dp[i]);
}

int countt=0;
for(int i=0;i<n;i+=1)
if(dp[i]==res){
int maxx=0;
for(set<string>::iterator k=G[i].begin();k!=G[i].end();k++){
int len=(*k).length();
maxx=max(maxx,len);
}
for(set<string>::iterator k=G[i].begin();k!=G[i].end();k++){
if(k->length()==maxx){
string s=(*k);
//cout<<s<<endl;
countt+=1;
}
}
}

printf("%d %d\n",res,countt);
}
return 0;
}


(2)

后来上网看了下他人的解法。

发现的确是高。其实并不需要记录每一条dp路径,而可以用一个path数组记录与dp相对应的法案数,

在dp过程中,将之前的,价格与当下相等的那个path值直接赋0(因为当前的path值一定大于等于之前的path),

这样之后不会重复加上方案数了。

自己在真正接受(原来只是看了一眼就自己敲了)这种想法之前还是自己敲了一个很难改的WA了的代码

详细错误在下面的代码注释里

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#define maxn 5005

using namespace std;
int a[maxn];
int dp[maxn];
int path[maxn];

int main()
{
int n;
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i+=1){
scanf("%d",&a[i]);
dp[i]=1;
path[i]=0;
}

int res=0;
for(int i=0;i<n;i+=1){
int maxx=0;
for(int j=0;j<i;j+=1){
if(a[j]>a[i]&&dp[j]+1>dp[i]){
dp[i]=dp[j]+1;
maxx=max(maxx,dp[j]);
}
}
set<int> s;
for(int j=0;j<i;j+=1){
if(a[j]>a[i]&&dp[j]==maxx&&!s.count(a[j])){
//这里错了,可以看看这组数据 100 6 5 2 98 97 2 1
//当ai==1的时候,会先计算第一个2的path值,这个时候
//2就被压入了set,之后path值更大的2就不能再加入计算了
path[i]+=(path[j]==0?1:path[j]);
s.insert(a[j]);
}
}
s.clear();
res=max(res,dp[i]);
}

set<int> s;
int countt=0;
for(int i=0;i<n;i+=1)
if(dp[i]==res&&s.count(a[i])==0){
s.insert(a[i]);
countt+=path[i];
}

printf("%d %d\n",res,countt);
}
return 0;
}


下面是ac代码

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string>
#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <numeric>
#include <functional>
#define maxn 5005

using namespace std;
int a[maxn];
int dp[maxn];
int path[maxn];

int main()
{
int n;
while(scanf("%d",&n)!=EOF){
for(int i=0;i<n;i+=1){
scanf("%d",&a[i]);
dp[i]=1;
path[i]=1;
}

int res=0;
for(int i=0;i<n;i+=1){
for(int j=0;j<i;j+=1){
if(a[i]<a[j]){
if(dp[j]+1>dp[i]){
dp[i]=dp[j]+1;
path[i]=path[j];
}
else if(dp[j]+1==dp[i]){
path[i]+=path[j];
}
}
else if(a[i]==a[j]){
path[j]=0;
}
}
res=max(res,dp[i]);
}

int countt=0;
for(int i=0;i<n;i+=1){
if(dp[i]==res){
countt+=path[i];
}
}

printf("%d %d\n",res,countt);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: