复盘:
- 当时看到第一眼觉得是个贪心,但不知道怎么使得结果最大
- 看完解题才知道是个披着羊皮的狼–完全背包
思路:
根据题目的意思 机器人到终点最少时间就是n(0为起点 n为终点)
- 如果 爆炸时间t小于n就代表不能炸掉妖怪输出0 return返回
- 其次可建墙壁的位置个数如果是1就不用考虑建墙壁 直接输出n就好了 因为建一个墙壁方向回不来
- 建墙壁至少是以来回为单位的 所有 两墙壁的距离乘2存于数组中备用
- 所有先假设跑完n后再加入 过程中来回徘徊的(可以徘徊无数次 只要在t的范围内)
- 因此就是 背包容量大小为t-n 最多可以放多少大小为俩墙壁距离的物品 最后输出最大结果加回原来的n
ACcode
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+3;
int tt,n,m,t;
int num[N];
int main(){
cin>>tt;
while(tt--){
cin>>n>>m>>t;
t-=n;//背包的大小
vector<int> v(m+1);
for(int i=1;i<=m;i++){
cin>>v[i];
}
sort(v.begin() + 1, v.end());
if(t<0){//走不到先炸开了
cout<<0<<endl;
continue;
}
if(m<=1){//一个墙壁无效果
cout<<n<<endl;
continue;
}
set<int> s;
for(int i=2;i<=m;i++){
s.insert(2*(v[i]-v[i-1]));
}
//完全背包模板
vector<bool> dp(t+1);
dp[0]=1;
for(auto val:s){
for(int i=val;i<=t;i++){
dp[i]=dp[i]|dp[i-val];//倍数才true
}
}
for(int i=t;t>=0;i--){
if(dp[i]!=0)
{
cout<<i+n<<endl;
break;
}
}
}
return 0;
}
核心代码解释
dp[0]=1;
for(auto val:s){
for(int i=val;i<=t;i++){
dp[i]=dp[i]|dp[i-val];//倍数才true
}
}
```
* 就是判断是否能遍历到这个值 dp[i]=dp[i]|dp[i-val];
* 按位或就是其中一个为true dp【i】 就为true【i-val] 如果出现了 就必然能出现i 因为当前就是在遍历val的倍数