在 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 时,此解决方案有啥问题?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 SPOJ GCD2 代码在 SPOJ 上出错?

SPOJ 的 CODE1 - 无法解决

用 2 x 1 多米诺骨牌填充 3xN 瓷砖的方法数(SPOJ:M3TILE)

如何在 mysql 中取消透视数据

智能合约从入门到精通:完整范例

在 SPOJ 上提交代码会导致运行时错误 (SIGABRT)