题目链接:https://vijos.org/p/1574
这道题是昨晚一个叫Ztravellers的大佬推荐的,确实觉得这是一道很有意思的题,很多方面都很有意思;
初见这道题,估计想法都是贪心,因为各方面都很符合贪心,正解也用到了贪心,不过是在dp前贪心的;
思路:
我们砍树收集金币,肯定是希望损失最小,为了损失最小,肯定要尽量先砍每天损失最大的,从这个思想可以看出我们是需要排序的。但是也不一定就是一定要损失最大的,为了答案最优,我们还需要一个dp来做这个过程。定义一个d[i][j]表示前i棵树中砍j棵,当然这个形容还有很多,比如:第j天的时候判断第i棵树砍不砍;
然后因为金币是掉落,为了避免出错,所以在转移方程时要和0比一下大小
状态转移方程:d[i][i]=max{0,d[i-1][j],d[i-1][j-1]-per[i]*(j-1)};per数组是每棵树每天会损失的金币
题很简单,思路也不难想,打题也就是两次过,所以就直接出代码了
PS:有一个小小的问题还不是很清楚,昨晚询问了众多大佬都未果,所以在这里问问各位大佬,为啥答案不一定存在d[n][k]??
上代码:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<cmath> 7 #include<queue> 8 #define maxn 1005 9 using namespace std; 10 11 struct node{ 12 int per,high; 13 }e[maxn]; 14 15 int comp(const void*a,const void*b) 16 { 17 return (*(struct node*)a).per>(*(struct node*)b).per?-1:1; 18 } 19 20 int d[maxn][maxn],n,k,ans; 21 22 int main() 23 { 24 while(scanf("%d%d",&n,&k)!=EOF) 25 { 26 memset(d,0,sizeof(d)); 27 if(n==0&&k==0)return 0; 28 for(int i=1;i<=n;i++) 29 scanf("%d",&e[i].high); 30 for(int i=1;i<=n;i++) 31 scanf("%d",&e[i].per); 32 e[0].per=0x3f3f3f; 33 qsort(e,n+1,sizeof(e[0]),comp); 34 int ans=0; 35 for(int i=1;i<=n;i++) 36 for(int j=1;j<=min(i,k);j++) 37 { 38 d[i][j]=max(0,max(d[i-1][j],d[i-1][j-1]+e[i].high-e[i].per*(j-1))); 39 ans=max(ans,d[i][j]); 40 } 41 // printf("%d\n",d[n][k]); 42 printf("%d\n",ans); 43 } 44 45 46 }