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 }
View Code

错误!递推式不成立,没有考虑当前决策对后续状态的影响。错误样例?自己找个标程对拍吧!

方法二:直接把状态对后面的影响算出来,,保证了无后效性。

 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 }
View Code

 此题在九月份错过一次。

BZOJ1694一样哦!然而又错了,一看原题一激动忘排序了。

posted @ 2017-09-03 23:38  Blue233333  阅读(241)  评论(0编辑  收藏  举报