BZOJ1742: [Usaco2005 nov]Grazing on the Run 边跑边吃草
数轴上n<=1000个点,从p出发以任意顺序走到所有的点,求到达每个点的时间之和的最小值。
好题!看起来水水的实际易错!
显然的结论是经过一个区间点之后肯定落在左端点或右端点上,谁没事最后还往中间跑呢!那就可以拍个序然后设计dp状态了,一个区间dp,f[i,j,0/1]表示走了区间i~j,最后落在左/右端点。
一个小技巧是把p算成一个点,初始化时之后p这个状态为0,其他都inf。那么问题来了!
方法一:记到状态的时间t[i,j,0/1],那么,相应更新t,其他同理。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #include<algorithm> 5 //#include<iostream> 6 using namespace std; 7 8 int n,p; 9 #define maxn 1011 10 int a[maxn],f[maxn][maxn][2],t[maxn][maxn][2]; 11 const int inf=0x3f3f3f3f; 12 int min(int a,int b) {return a<b?a:b;} 13 int main() 14 { 15 scanf("%d%d",&n,&p); 16 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 17 sort(a+1,a+1+n); 18 for (int i=1;i<=n;i++) f[i][i][0]=f[i][i][1]=t[i][i][0]=t[i][i][1]=inf; 19 a[n+1]=inf;int pos; 20 for (pos=1;pos<=n+1;pos++) if (a[pos]>p) break; 21 if (pos==n+1) t[n][n][0]=t[n][n][1]=f[n][n][0]=f[n][n][1]=p-a[n]; 22 else if (pos==1) t[1][1][0]=t[1][1][1]=f[1][1][0]=f[1][1][1]=a[1]-p; 23 else f[pos][pos][0]=f[pos][pos][1]=a[pos]-p,f[pos-1][pos-1][0]=f[pos-1][pos-1][1]=p-a[pos-1], 24 t[pos][pos][0]=t[pos][pos][1]=a[pos]-p,t[pos-1][pos-1][0]=t[pos-1][pos-1][1]=p-a[pos-1]; 25 for (int len=1;len<n;len++) 26 for (int i=1;i<=n-len;i++) 27 { 28 const int j=i+len; 29 if (f[i+1][j][0]+t[i+1][j][0]+a[i+1]-a[i]<f[i+1][j][1]+t[i+1][j][1]+a[j]-a[i]) 30 { 31 t[i][j][0]=t[i+1][j][0]+a[i+1]-a[i]; 32 f[i][j][0]=f[i+1][j][0]+t[i][j][0]; 33 } 34 else 35 { 36 t[i][j][0]=t[i+1][j][1]+a[j]-a[i]; 37 f[i][j][0]=f[i+1][j][1]+t[i][j][0]; 38 } 39 if (f[i][j-1][0]+t[i][j-1][0]+a[j]-a[i]<f[i][j-1][1]+t[i][j-1][1]+a[j]-a[j-1]) 40 { 41 t[i][j][1]=t[i][j-1][0]+a[j]-a[i]; 42 f[i][j][1]=f[i][j-1][0]+t[i][j][1]; 43 } 44 else 45 { 46 t[i][j][1]=t[i][j-1][1]+a[j]-a[j-1]; 47 f[i][j][1]=f[i][j-1][1]+t[i][j][1]; 48 } 49 f[i][j][0]=min(f[i][j][0],inf); 50 f[i][j][1]=min(f[i][j][1],inf); 51 } 52 printf("%d\n",min(f[1][n][0],f[1][n][1])); 53 return 0; 54 }
错误!递推式不成立,没有考虑当前决策对后续状态的影响。错误样例?自己找个标程对拍吧!
方法二:直接把状态对后面的影响算出来,,保证了无后效性。
1 #include<stdio.h> 2 #include<string.h> 3 #include<stdlib.h> 4 #include<algorithm> 5 //#include<iostream> 6 using namespace std; 7 8 int n,p; 9 #define maxn 1011 10 int a[maxn],f[maxn][maxn][2]; 11 const int inf=0x3f3f3f3f; 12 int min(int a,int b) {return a<b?a:b;} 13 int main() 14 { 15 scanf("%d%d",&n,&p); 16 for (int i=1;i<=n;i++) scanf("%d",&a[i]); 17 a[++n]=p; 18 sort(a+1,a+1+n); 19 for (int i=1;i<=n;i++) 20 { 21 if (a[i]!=p) f[i][i][0]=f[i][i][1]=inf; 22 else f[i][i][0]=f[i][i][1]=0; 23 } 24 for (int len=1;len<n;len++) 25 for (int i=1;i<=n-len;i++) 26 { 27 const int j=i+len; 28 f[i][j][0]=min(inf,min(f[i+1][j][0]+(n-j+i)*(a[i+1]-a[i]),f[i+1][j][1]+(n-j+i)*(a[j]-a[i]))); 29 f[i][j][1]=min(inf,min(f[i][j-1][0]+(n-j+i)*(a[j]-a[i]),f[i][j-1][1]+(n-j+i)*(a[j]-a[j-1]))); 30 } 31 printf("%d\n",min(f[1][n][0],f[1][n][1])); 32 return 0; 33 }
此题在九月份错过一次。
BZOJ1694一样哦!然而又错了,一看原题一激动忘排序了。