[dp] Jzoj P5770 可爱精灵宝贝
90%题解
- 其实就是一个水法,只考虑一个折回的话
- 直接枚举到左端点折回或到右端点折回
- 暴力判断
100%题解
- 对于数据,是不只有一个折回的,因为会存在一种这样的情况:
- 向左走到某个点后,向右边恰好有一个点的时间可行,然后到了这个点后,左边又有一个点恰好时间可行,这样就不止一个折回了
- 考虑一下dp
- 设f[t][l][r][0/1]表示 当前时间为t 走过的区间为[l,r] 0表示在l 1表示在r 的最大分数
- 那么对于[l,r]中间的点可以不用管,这时可以肯定的
- 考虑如何转移,如果当前在l,可以考虑走到l-1或者到r再走到r+1
- 如果在r,可以考虑走到r+1或者走到l再走到l-1
- 最后的ans就是在dp转移过程中求max
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <cmath> 6 using namespace std; 7 struct edge{int a,b,t;}e[1010]; 8 int f[2005][103][103][2],n,m,k,ans,mx,w; 9 bool cmp(edge x,edge y){ return x.a<y.a; } 10 int dis(int x,int y) { return abs(e[x].a-e[y].a); } 11 int main() 12 { 13 //freopen("go.in","r",stdin); 14 //freopen("go.out","w",stdout); 15 scanf("%d%d%d",&n,&k,&m); 16 for (int i=1;i<=m;i++) scanf("%d%d%d",&e[i].a,&e[i].b,&e[i].t),mx=max(mx,e[i].t); 17 m++,e[m]=edge{k,0,mx}; 18 sort(e+1,e+m+1,cmp); 19 memset(f,-63,sizeof(f)); 20 for (int i=1;i<=m;i++) 21 if (e[i].a==k&&e[i].b==0) 22 w=i; 23 f[0][w][w][0]=f[0][w][w][1]=0; 24 for (int i=w-1;i>=1;i--) 25 { 26 int tim=e[w].a-e[i].a; 27 f[tim][i][w][0]=f[dis(w,i+1)][i+1][w][0]+((tim<e[i].t)?e[i].b:0); 28 ans=max(ans,f[tim][i][w][0]); 29 } 30 for (int i=w+1;i<=m;i++) 31 { 32 int tim=e[i].a-e[w].a; 33 f[tim][w][i][1]=f[dis(i-1,w)][w][i-1][1]+((tim<e[i].t)?e[i].b:0); 34 ans=max(ans,f[tim][w][i][1]); 35 } 36 for (int i=1;i<=mx;i++) 37 for (int l=1;l<=w-1;l++) 38 for (int r=w+1;r<=m;r++) 39 { 40 f[i][l][r][0]=max(f[max(i-dis(l,l+1),0)][l+1][r][0],f[max(i-dis(l,r),0)][l+1][r][1])+((i<e[l].t)?e[l].b:0); 41 f[i][l][r][1]=max(f[max(i-dis(r-1,r),0)][l][r-1][1],f[max(i-dis(l,r),0)][l][r-1][0])+((i<e[r].t)?e[r].b:0); 42 ans=max(ans,max(f[i][l][r][0],f[i][l][r][1])); 43 } 44 printf("%d",ans); 45 return 0; 46 }