NOIP模拟18 T2

不知道为什么很多人拒绝这题打搜索。。。其实搜索在充分剪枝后时间是非常优秀的,不管数据怎样基本都可跑出

  首先一个显然结论:对于某种状态,他抓到的小精灵一定是一个连续的区间。

  因此我们可以枚举这个区间的左右端点,进行搜索,但是这样显然会T,我们考虑剪枝:

  1.可行性剪枝,当前时间大于最大时间直接return(废话)

  2.最优性剪枝,对于每种状态,我们用两个数组来记录出现这种状态所需要的最短时间,以及最短时间下的最优答案,若时间长答案还小,直接return

  3.确定枚举方向,如果上一步从左向右走,那么当前必然向左走。很显然,若继续向右走,与上一次枚举的有重复。

  4.一个比较玄学但是非常有用的剪枝:对于当前左右端点l,r,在枚举右端点时,从m处开始枚举到r+1,而不是从r+1枚举到m,左端点同理。看上去比较玄学,实际上是有一定原理的:若我们枚举到的端点离当前端点很近,那么会重复走很多位置,在大多数情况下浪费时间,往往无法得到最优解,而较远端点更可能获得更优的答案,结合剪枝2,会将较近端点剪掉,除去很多不必要搜索。

  综合以上,我们就可以得到一个时间碾压正解的搜索(欢迎造数据hack)

  附代码:

 1 #include<bits/stdc++.h>
 2 #define cri const register int
 3 using namespace std;
 4 int n,k,m,maxt,ans,ys[2005],yx[2005],f[105][105],ff[105][105];
 5 char v[105];
 6 inline int abs(int x){return x<0?-x:x;}
 7 struct jing{
 8     int a,b,t;
 9     friend bool operator < (jing a,jing b){
10         return a.a<b.a;
11     }
12 }c[105];
13 void dfs(cri ti,cri l,cri r,cri na,cri o){
14     if(ti<maxt)ans=max(ans,na);
15     if(ti>=maxt)return;
16     if(ti>=f[l][r]&&na<=ff[l][r]){
17         return;
18     }
19     if(f[l][r]>ti)f[l][r]=ti,ff[l][r]=na;
20     if(o!=0){
21         int sum=0;
22         for(int i=m+1;i>=r+1;i--)
23             if(ti+c[i].a-c[l].a<=c[i].t)
24                 sum+=c[i].b;
25         for(int i=m+1;i>=r+1;i--){
26             if(ti+c[i].a-c[l].a<=c[i].t){
27                 dfs(ti+c[i].a-c[l].a,l,i,na+sum,0);
28                 sum-=c[i].b;
29             }
30         }
31     }
32     if(o!=1){
33         int sum=0;
34         for(int i=l-1;i>=1;i--){
35             if(ti+c[r].a-c[i].a<=c[i].t){
36                 sum+=c[i].b;
37             }
38         }
39         for(int i=1;i<=l-1;i++){
40             if(ti+c[r].a-c[i].a<=c[i].t){
41                 dfs(ti+c[r].a-c[i].a,i,r,na+sum,1);
42                 sum-=c[i].b;
43             }
44         }
45     }
46 }
47 inline int read(){
48     int x=0;
49     char ch=getchar();
50     while(ch<'0'||ch>'9')ch=getchar();
51     while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-48,ch=getchar();
52     return x;
53 }
54 int main(){
55     memset(f,0x3f,sizeof(f));
56     scanf("%d%d%d",&n,&k,&m);
57     for(int i=1;i<=m;i++)
58         c[i].a=read(),c[i].b=read(),c[i].t=read(),maxt=max(maxt,c[i].t);
59     c[m+1].a=k;c[m+1].b=0,c[m+1].t=0;
60     maxt++;
61     sort(c+1,c+m+2);
62     for(int i=1;i<=m+1;i++)
63         ys[c[i].a]+=c[i].b,yx[c[i].a]=i;
64     dfs(1,yx[k],yx[k],ys[k],-1);
65     printf("%d",ans);
66     return 0;
67 }
View Code

 

posted @ 2019-08-12 21:28  tdcp  阅读(148)  评论(3编辑  收藏  举报