可爱精灵宝贝 DP/爆搜

考崩了

T2

这题是个DP的好题啊(凡是我不会的都是好题,所以所有的题都是好题(雾))

DP思路:

分析性质:这个人对于路上的小精灵,能收集就一定会收集,即他每次都会收集这一段区间的小精灵

然后就考虑DP

设f[i][j][t]表示经过从i到j的区间最后停在i,最终时刻为t可以收获的最大价值

g[i][j][t]表示经过从i到j的区间最后停在j,最终时刻为t可以收获的最大价值。

一步步往外拓展,转移方程式太长了见代码

 1 #include<bits/stdc++.h>
 2 #define M 105
 3 #define N 1005
 4 using namespace std;
 5 int f[M][M][N*2],g[M][M][N*2];
 6 struct node{
 7     int A,B,T;
 8 }jl[M];
 9 bool cmp(const node a,const node b)
10 {
11     return a.A<b.A||(a.A==b.A&&a.T<b.T);
12 }
13 int main()
14 {
15     memset(f,-0x3f,sizeof(f));
16     memset(g,-0x3f,sizeof(g));
17     int n,k,m,MAXT=0,ans=0;
18     scanf("%d%d%d",&n,&k,&m);
19     for(int i=1;i<=m;i++)scanf("%d%d%d",&jl[i].A,&jl[i].B,&jl[i].T),MAXT=max(MAXT,jl[i].T);
20     jl[m+1].A=k;jl[m+1].B=0;jl[m+1].T=0;
21     sort(jl+1,jl+m+2,cmp);
22     for(int i=1;i<=m+1;i++)
23         if(jl[i].A==k&&jl[i].B==0)
24         {
25             f[i][i][1]=g[i][i][1]=0;
26             break;
27         }
28     for(int t=1;t<=MAXT;t++)
29         for(int i=1;i<=m+1;i++)
30             for(int j=i;j<=m+1;j++)
31             {
32                 ans=max(ans,max(g[i][j][t],f[i][j][t]));
33                 f[i-1][j][t+jl[i].A-jl[i-1].A]=max(f[i][j][t]+(t+jl[i].A-jl[i-1].A<=jl[i-1].T?jl[i-1].B:0),f[i-1][j][t+jl[i].A-jl[i-1].A]);
34                 f[i-1][j][t+jl[j].A-jl[i-1].A]=max(g[i][j][t]+(t+jl[j].A-jl[i-1].A<=jl[i-1].T?jl[i-1].B:0),f[i-1][j][t+jl[j].A-jl[i-1].A]);
35                 g[i][j+1][t+jl[j+1].A-jl[i].A]=max(f[i][j][t]+(t+jl[j+1].A-jl[i].A<=jl[j+1].T?jl[j+1].B:0),g[i][j+1][t+jl[j+1].A-jl[i].A]);
36                 g[i][j+1][t+jl[j+1].A-jl[j].A]=max(g[i][j][t]+(t+jl[j+1].A-jl[j].A<=jl[j+1].T?jl[j+1].B:0),g[i][j+1][t+jl[j+1].A-jl[j].A]);
37             }
38     cout<<ans<<endl;
39     return 0;
40 }
DP 2000ms

这题可以用搜索过掉,而且跑的飞快。

主要是维护一个指针,及时筛掉不能去的点。

 1 #include<bits/stdc++.h>
 2 #define M 105
 3 #define N 1005
 4 using namespace std;
 5 int ans=0,MAXT,n,m,k,sum[M];
 6 struct node{
 7     int A,B,T;
 8 }jl[M];
 9 bool cmp(const node a,const node b){return a.A<b.A||(a.A==b.A&&a.T<b.T);}
10 void dfs(int now,int tim,int val,int tl,int tr)
11 {
12     if(val+sum[tl]+sum[m+1]-sum[tr-1]<ans)return ;//小剪枝
13     if(tim>MAXT)return ;
14     ans=max(ans,val);
15 
16     while(tl>=1&&tim+jl[now].A-jl[tl].A>jl[tl].T)tl--;
17     while(tr<=m+1&&tim+abs(jl[now].A-jl[tr].A)>jl[tr].T)tr++;//大剪枝
18 
19     if(tl>=1){
20         int tmp=tl;
21         dfs(tmp,tim+jl[now].A-jl[tmp].A,val+(tim+jl[now].A-jl[tmp].A<=jl[tmp].T)*jl[tmp].B,tl-1,tr);
22     }
23     if(tr<=m+1){
24         int tmp=tr;
25         dfs(tmp,tim+jl[tmp].A-jl[now].A,val+(tim+jl[tmp].A-jl[now].A<=jl[tmp].T)*jl[tmp].B,tl,tr+1);
26         }
27     return ;
28 }
29 int main()
30 {
31     scanf("%d%d%d",&n,&k,&m);
32     for(int i=1;i<=m;i++)scanf("%d%d%d",&jl[i].A,&jl[i].B,&jl[i].T),MAXT=max(MAXT,jl[i].T);
33     jl[m+1].A=k;jl[m+1].B=0;jl[m+1].T=0;
34     sort(jl+1,jl+m+2,cmp);
35     for(int i=1;i<=m+1;i++)sum[i]=sum[i-1]+jl[i].B;
36     for(int i=1;i<=m+1;i++)
37         if(jl[i].B==0){
38             dfs(i,1,0,i-1,i+1);break;
39         }
40     cout<<ans<<endl;
41     return 0;
42 }
搜索20ms

这个题对那些大佬来说是水题,但对我来说却不是。  

我的考试思路:

这题显然DP啊,然后呢?抓住m比较小,先把坐标离散了,然后。。。。。。。。

然后我就不会了,打了个30分的状压,状压还没裸暴力分高=_=

1.注意思路的转化,多见一些题。

2.一条路走不通的时候,换一条路走走。

3.暴力大法好哇!!!!(注意优化)

原文地址:https://www.cnblogs.com/hzoi-kx/p/11342001.html