关于本题数据正确性与贪心方法正确性的讨论
查看原帖
关于本题数据正确性与贪心方法正确性的讨论
484910
SwordDance楼主2023/6/27 16:31

截止目前(2023.6.27)本题共37提交40通过,无题解。 根据本人做题时的思考与某大佬讨论帖发表此讨论。

首先,本题与UVa10833几乎一样,而那道题的暴力法AC代码仅修格式改后在本题60pts,贪心法WA代码仅修改格式后100pts。(详见上述讨论帖)

而贪心法的答案普遍>=暴力法。同时经过蒟蒻本人手动演算, 暴力法的答案是正确的。 结合两道几乎一致的题对于相同代码答案结果判定不同,本人合理怀疑此题数据答案是否正确。

声明:本人同样写了一种贪心代码AC此题,和上述讨论帖内的贪心代码思路略有不同,但经过500组数据对拍结果全部一样,为此应该可以代表贪心算法。本人具体贪心方法不详写,肯定不是因为懒,可以参考上述讨论贴的方法。

Hack:

比如数据5 7 9。 暴力算法和贪心算法在前7天的施肥方法是一样的。最后得到的月亮树高度依次是:10 6 5 1 0 -1 -1 -1 -1(-1表示尚未播种)

此时,贪心算法会给第3棵月亮输施肥。使第八天时第三棵树达到高度h2从而获得种子。

贪心算法后续月亮树高度依次为:

第八天:11 7 7 2 1 0 0 -1 -1

第九天:12 8 8 4 2 1 1 -1 -1

第十天:13 9 9 6 3 2 2 0 -1

第十一天:14 10 10 7 5 3 3 1 0

此时答案为:4+4+7+9+11+11+13+14+11=84

而正解情况应该是:

第八天:11 7 6 3 1 0 -1 -1 -1

第九天:12 8 7 5 2 1 0 0 -1

第十天:13 9 8 7 3 2 1 1 0

此时答案为:4+5+6+10+11+12+12+13+10=83

综上

贪心算法会优先选择给能更快到达h1或h2的月亮树施肥,从而更快获得种子。但这仅是局部最优。因为月亮树达到h2之后的生长不能再带来种子收益。

倘若先给其他月亮树施肥达到h1乃至h2,于此同时高的月亮树会自然生长到h2。从而在同样的时间内获得更多种子,从而得到更短的答案。

为此,这种贪心方法不能得到正确的答案。

最后,附上本人代码(AC此题,但答案应该不对)

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=102;
int h1,h2,n,ans,a[N],t1=2,t2=3,g,sum,st=4;
bool _;
int main()
{
    scanf("%d%d%d",&h1,&h2,&n);
    if(h1>h2) swap(h1,h2);
    if(h1&1){
    	sum=h1/2+1;
     	a[1]=h1+1+sum;
     	a[2]=h1;g=1;
    }
    else{
    	sum=h1/2;
    	a[1]=h1+sum;
    	a[2]=h1;
    }
    ans=sum*2;
    if(a[1]>=h2) _=1,a[3]=a[1]-h2,st=5;
    if(a[1]<=h2) a[2]+=g,g=0;
    if(h1==h2&&(h1&1)) a[3]--;
    for(int i=st;i<=n;i++){
    	int num1=h2-a[t1]-g;
    	int num2=h1-a[t2]-g;
    	if(a[t2]==0) num2+=g;
    	if((num1+1)/2<(num2+1)/2){
    	    g=0;
    	    sum=(num1+1)/2;
    	    if(num1&1) g=1;
    	    a[t1++]=h2-sum;
	}
	else{
	    if(a[t2]==0) a[t1]+=g;
    	    g=0;
            sum=(num2+1)/2;
    	    if(num2&1) g=1;
    	    a[t2++]=h1-sum;
	}
	if(a[1]+sum>=h2&&!_)
            _=1,a[i++]=a[1]-h2;
	for(int j=1;j<i;j++) a[j]+=sum;
		ans+=sum;
    }
    for(int i=2;i<=n;i++) ans+=a[1]-a[i];
    printf("%d",ans-g);
    return 0;
}
2023/6/27 16:31
加载中...