P7366 [CTSC2002]月亮森林
首先可以知道,第二棵和以后的树,越早开始生长越好。
当
在第一棵树还没结种子时,只能给第一棵树施肥, 因此无脑施肥到第一棵树结第一颗种子。
但是可以很明显地观察到
如果再给第一棵树施肥来获取第二颗种子,实际上最好情况下仅仅是让第三棵和以后的树早一天开始生长。
那么这早的一天为了弥补第一棵树多生长的1单位长度而没用了,第二棵树反倒落下1单位长度。
因此,第一棵树结第一颗种子后,就把它晾在那吧(逃
还有一个显而易见的结论:
如果一棵树已经结了第二颗种子,或自然生长1单位长度后要第二颗种子,那么它就再也不用被施肥了。
因为如果给它施肥是浪费,还不如给更矮的树施肥催种子。
那么施肥的时间可以改为第二天收种子前,立即见效。
在此前提下,我们有一个贪心策略:给距离结种子最近的树施肥。
即:设当前有
该贪心策略在大部分情况下是正确的,并能通过本题。
至于为什么是“大部分”,详见 Hack
示例程序
该代码由提交向UVa10833的WA代码适当修改而成,在该题能AC(大雾
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,Hp[5],H[100],State[100];
int main(){
cin>>Hp[0]>>Hp[1]>>m;n=1;
Hp[2]=inf;
for(int i=0;i<m;i++)
{H[i]=0;State[i]=0;}
int ans=0;
while(n<m){
ans++;
int tn=n;
for(int i=0;i<tn;i++){//tree grow,seed produce and plant
H[i]++;
if(H[i]>=Hp[State[i]])
{State[i]++;n++;}
}
int pouron;//Try to pour magic water for tomorrow
if(tn==1)pouron=0;
else{
int i,j;
for(i=1;i<tn;i++)
if(State[i]<2)break;
for(j=i;j<tn;j++)
if(State[j]==0)break;
if(j>=tn||State[j]!=0)pouron=i;
else pouron=((Hp[1]-H[i])/2<(Hp[0]-H[j])/2)?i:j;
}
H[pouron]++;
if(H[pouron]>=Hp[State[pouron]])
{State[pouron]++;n++;}
}
for(int i=1;i<m;i++)
ans+=H[0]-H[i];
cout<<ans<<endl;
return 0;
}
Hack
| 编号 | 输入数据 | 正确输出 | 示例程序输出 |
|---|---|---|---|
| 1 | 7 8 8 | 88 | 89 |
| 2 | 7 8 16 | 244 | 247 |
上述数据都不在官方数据中,或官方实际上不知道这些数据的存在,或者官方的标准程序与示例程序实现相似或相同。贪心算法对这些数据无效,并且目前没有已知有效算法能够兼顾这些数据。
另附UVa10833 AC Code:(暴力法,修改后在该题成绩60)
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
int m,Hp[5],H[20],State[20];
int dfs(int cnt,int cur){
if(cnt>=m){
int ans=0;
for(int i=1;i<m;i++)
ans+=H[0]-H[i];
return ans;
}
int ans=inf,newcnt=cnt;
for(int i=0;i<cnt;i++){
H[i]++;
while(H[i]>=Hp[State[i]])
{State[i]++;newcnt++;}
}
if(cur+1<cnt&&State[cur+1]<2){
int hh=H[cur+1],ss=State[cur+1],cc=newcnt;
H[cur+1]++;
while(H[cur+1]>=Hp[State[cur+1]])
{State[cur+1]++;newcnt++;}
ans=min(ans,dfs(newcnt,cur+1));
H[cur+1]=hh;State[cur+1]=ss;newcnt=cc;
}
{
int pouron;//Try to pour magic water for tomorrow
if(cnt==1)pouron=0;
else{
int i,j;
for(i=1;i<cnt;i++)
if(State[i]<2)break;
for(j=i;j<cnt;j++)
if(State[j]==0)break;
if(j>=cnt||State[j]!=0)pouron=i;
else pouron=((Hp[1]-H[i])/2<(Hp[0]-H[j])/2)?i:j;
}
int hh=H[pouron],ss=State[pouron],cc=newcnt;
H[pouron]++;
if(H[pouron]>=Hp[State[pouron]])
{State[pouron]++;newcnt++;}
ans=min(ans,dfs(newcnt,pouron));
H[pouron]=hh;State[pouron]=ss;newcnt=cc;
}
for(int i=0;i<cnt;i++){
H[i]--;
while(H[i]<Hp[State[i]-1])
State[i]--;
}
return 1+ans;
}
int main(){int o,_o=1;
for(cin>>o;_o<=o;_o++){
cin>>Hp[0]>>Hp[1]>>m;
Hp[2]=inf;
for(int i=0;i<m;i++)
{H[i]=0;State[i]=0;}
cout<<"Case "<<_o<<": ";
if(m==1)cout<<1<<endl;
else cout<<dfs(1,0)<<endl;
}
return 0;
}