2012年"浪潮杯"山东省第三届ACM大学生程序设计竞赛 Fruit Ninja I
题意:
水果忍者,给你n个水果的出现时间,出现位置,和他是否是好水果,切到好水果+1,切到坏水果-1,连续切到三次以上分数加倍。
每次只能切一刀,两刀之间的间隔大于等于m
问怎样安排能使得分最大;
解法:先求出每一秒出手能得到的最大的得分,双重暴力,
再用DP求出手时间;
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <stdio.h> using namespace std; int s[10010][220],maxn[10010],vis1[10010],dp[10010],vis2[10010]; int main() { int T,n,m,a,b,c; scanf("%d",&T); int t=1; while(T--) { scanf("%d%d",&n,&m); memset(s,0,sizeof(s)); memset(vis1,0,sizeof(vis1)); memset(maxn,0,sizeof(maxn)); memset(vis2,0,sizeof(vis2)); for(int i=0; i<n; i++) { scanf("%d%d%d",&a,&b,&c); if(b==0) { s[a][c]=1; } else if(b==1) { s[a][c]=-1; } vis1[a]=1; if(c>vis2[a])//优化,算出最右边的位置 { vis2[a]=c; } } for(int i=1; i<=10000; i++)//算出每一秒出手时能切到的最大分数 { if(vis1[i]==1) { int max1=-1; for(int j=1; j<=vis2[i]; j++) { int f=0; int sum=0; for(int k=j; k<=vis2[i]; k++) { if(s[i][k]==1) { f++; } else if(s[i][k]==-1) { if(f>=3) { sum+=f*2; if(sum>max1) { max1=sum; } } else { sum+=f; if(sum>max1) { max1=sum; } } f=0; sum-=1; if(sum>max1) { max1=sum; } } } if(f>0) { if(f>=3) { sum+=f*2; if(sum>max1) { max1=sum; } } else { sum+=f; if(sum>max1) { max1=sum; } } } } maxn[i]=max1; } } memset(dp,0,sizeof(dp)); for(int i=1; i<=10000; i++)//DP,决定哪一秒钟出手 { if(i>m) { dp[i]=max(dp[i-1],dp[i-m-1]+maxn[i]);//如果出手,则和他i-m-1时候的状态有关系 } else { dp[i]=max(dp[i-1],maxn[i]); } } printf("Case %d: ",t++); printf("%d\n",dp[10000]); } return 0; }