在 SPOJ 上解决 JUICE 时,此解决方案有啥问题?
Posted
技术标签:
【中文标题】在 SPOJ 上解决 JUICE 时,此解决方案有啥问题?【英文标题】:What is wrong with this solution while solving JUICE on SPOJ?在 SPOJ 上解决 JUICE 时,此解决方案有什么问题? 【发布时间】:2015-04-27 16:54:07 【问题描述】:问题是:
杰瑞在有趣的游戏中迷失了自己:水果忍者。 Fruit Ninja 是一款 iPhone 和 iPad 的游戏,玩家在其中切下屏幕底部的水果,并通过单片切两个以上的水果获得奖励。水果一旦被切开,就会碎成小块,不能再切了。
经过几个月的训练,他成为了这款游戏的专家。实际上,他可以随时切掉屏幕上所有的水果。杰瑞还有一个坏习惯,就是不愿意为以后的砍伐留下一些果实。也就是说,杰瑞切完水果后,屏幕上的所有水果都碎了,没有人离开。这就是为什么他所有的朋友都称他为榨汁机。
现在他只考虑奖金,当他切两个以上的水果时,他可以获得与他当时切水果数量相同的一些奖金分数。例如,如果 Jerry 用一片切了 4 个水果,他可以从这片中得到 4 分。
Jerry 拿到水果时间表后,就知道每个水果的出现时间和消失时间。他只能在水果的出现时间和消失时间之间将水果切成碎片。他想知道他可以获得的最大可能奖励分数。
输入
有几个测试用例;输入的第一行包含一个整数 T,表示测试用例的数量。 (T
对于每个测试用例,第一行包含一个整数 N,表示水果的总数。 (1
接下来的 N 行,每行描述一个水果。对于每一行,有两个整数 Xi 和 Yi,其中 Xi 是果实的出现时间,Yi 是该果实的消失时间。 (0
输出
对于每个测试用例,输出一个整数,表示 Jerry 可能获得的最高分数。有关详细信息,请参阅示例。
例子
输入: 1 10 1 10 2 11 3 12 4 13 13 14 14 15 13 19 20 22 21 23 22 24
输出: 案例#1:10
这里是代码: 它根据开始时间对时间间隔进行排序。dp[i] 考虑了第 i 个水果出现的时间。我们只会在水果出现时进行切割,因为它会涵盖所有情况
#include<iostream>
#include<vector>
#include<algorithm>
#include<memory.h>
using namespace std;
struct node
int x,y;
;
int cmp(node a,node b)
if(a.x!=b.x)
return a.x<b.x;
return a.y<b.y;
int main()
int test;
cin>>test;
int t=0;
int dp[1002];
while(test--)
t++;
int n;
cin>>n;
vector<node> v(n);
for(int i=0;i<n;i++)
int a,b;
cin>>a>>b;
v[i].x=a;
v[i].y=b;
sort(v.begin(),v.end(),cmp);
memset(dp,0,sizeof(dp));
int mx=0;
for(int i=0;i<n;i++)
int id=100000,match=0;
for(int j=0;j<=i;j++)
if(v[j].y>=v[i].x)
id=min(id,j);
match++;
for(int j=id;j<=i;j++)
if(match>2)
dp[i+1]=max(dp[i+1],dp[j]+match);
else
dp[i+1]=max(dp[i+1],dp[j]);
if(v[j].y>=v[i].x)
match--;
dp[i+1]=max(dp[i+1],dp[i]);
mx=max(mx,dp[i+1]);
cout<<"Case #"<<t<<": "<<mx<<"\n";
return 0;
【问题讨论】:
你应该在帖子中真正包含你想要回答的实际问题,而不仅仅是标题...... 当你问你的代码有什么问题时,你必须指定预期的输出和你的输出。在这种情况下,您必须添加问题的链接。 添加问题描述 【参考方案1】:当某些片段开始时间相同时,这可能是错误的。
我用你的代码运行这个测试用例:
10
1 1
1 2
3 3
1 4
3 5
3 6
3 7
8 8
3 9
3 10
您的代码输出 10 但答案实际上是 9
因为这个测试用例,我也有几个 WA, 并在我处理完此案后获得了 AC...我将分享我的经验,请看看它是否对您来说是同样的错误。
使用这个测试用例,我的代码会输出10,我会快速解释如下:
令 dp(i) 为您在第 i 段开始时间进行最后一次剪辑的状态
显然,对于所有 j ,dp(i) = 最大值 (dp(j) + # of segment(after j)intersect with i-th segment)
从物理上讲,这意味着 你在第 j 个片段的开始时间有倒数第二个片段,如果 第 j 个片段和第 i 个片段是合乎逻辑的 except开始时间是一样的!那么它不是2个不同的切割而是相同的切割!
要解决这个问题,正确的方法是只选择具有相同开始时间的连续片段的最后一个片段!
(假设段已经按照开始时间排序,下面的顺序就是排序顺序)
这是错误,我的程序(也许你的程序也是如此)给出了输出 10,因为(使用基于 0)
DP(9) = DP(6) + # [7,9] 中的重叠段
= 7 + 3 = 10!
如果你看得更深,DP(6) = 7 实际上是对的,因为它没有考虑之后的段。但是您不应该使用 DP(6) 来更新 X>6 的任何 DP(X)! 因为 具有相同开始时间的最后一段(第 6 段)是 8-第一段
简而言之,如果我们使用某个不是最后一个与自身具有相同开始时间的 DP 状态来更新其他 DP 状态,则可能会出现问题。
我的解决方案是,当我在第 i 个段上做 DP 时,每当我发现一些段 j 与段 i (j 我将 DP(j) 设置为负无穷大 这样它就不能优化到足以更新其他状态。
已编辑:已添加接受的代码 根据 OP 的要求,以下是我接受的代码
#include<bits/stdc++.h>
#define pii pair<int,int>
#define x first
#define y second
#define INF 1LL<<28
using namespace std;
int T,n;
int dp[1005];
pii a[1005];
int main()
scanf("%d", &T);
for(int qwe=1; qwe <= T; qwe++)
scanf("%d", &n);
for(int i=0; i<n;i++) scanf("%d%d", &a[i].x, &a[i].y);
sort(a, a+n);
memset(dp,0,sizeof(dp));
for(int i=0; i<n;i++)
int cnt = 0;
for(int j=i-1; j>=0; j--)
if(a[j].x == a[i].x)dp[j] = -INF; cnt++; continue;
cnt += (a[i].x >= a[j+1].x && a[i].x <= a[j+1].y);
dp[i] = max(dp[i], dp[j] + (cnt>2? cnt:0));
cnt += (a[i].x >= a[0].x && a[i].x <= a[0].y);
dp[i] = max(dp[i], (cnt>2? cnt:0));
printf("Case #%d: %d\n", qwe, dp[n-1]);
return 0;
【讨论】:
是的,如果我能告诉我我的回答对你有帮助以上是关于在 SPOJ 上解决 JUICE 时,此解决方案有啥问题?的主要内容,如果未能解决你的问题,请参考以下文章