标签:bag 暴搜 超过 开始 nbsp read getchar 返回 数组
1. solution 1 普通dfs 60pt
2. solution 2 记忆化搜索 100pt
3. solution 3 到达型 01 背包
4. PS CE 的原因
dfs 暴搜,pos 记录当前到了第几首歌,level 记录当前的音量
由于每换一首歌都要调节音量,也就是要么 + 下一首音量,要么 - 下一首歌音量。那么当我们发现无论是上调音量还是下降音量都不能满足 [ 0,maxlevel ] 的音量区间,那么直接 return 掉就好了,也就是我们只转移合法的音量
ans 记录答案,可以初始化 -1 ,不合法的答案输出 -1
但是普通dfs会TLE啊
//60 pt dfs #include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<string> #include<cstring> #include<queue> using namespace std; typedef long long ll; inline int read() { int ans=0; char last=‘ ‘,ch=getchar(); while(ch<‘0‘||ch>‘9‘) last=ch,ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘) ans=ans*10+ch-‘0‘,ch=getchar(); if(last==‘-‘) ans=-ans; return ans; } int n,star,maxl; int a[105]; int ans=-1; void dfs(int pos,int level) { if(pos>n){ans=max(ans,level);return;} if(level+a[pos]>maxl&&level-a[pos]<0) return; if(level+a[pos]<=maxl&&level+a[pos]>=0) dfs(pos+1,level+a[pos]); if(level-a[pos]<=maxl&&level-a[pos]>=0) dfs(pos+1,level-a[pos]); } int main() { n=read();star=read();maxl=read(); for(int i=1;i<=n;i++) a[i]=read(); dfs(1,star); printf("%d\n",ans); return 0; }
f [ i ][ j ] 也就是 f [ pos ][ level ] 前 i 首歌音量不超过 j 的最大音量
初始化 -1
记忆化避免了重复搜索,开数组的目的其实是记录下当前状态在之前有没有被搜到过,如果搜到过直接返回它
(其实后面改DP的时候发现 f 数组里面可以没有实际内容,只是记录下有没有搜到过罢了)
//100 pt ji yi hua dfs #include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<string> #include<cstring> #include<queue> using namespace std; typedef long long ll; inline int read() { int ans=0; char last=‘ ‘,ch=getchar(); while(ch<‘0‘||ch>‘9‘) last=ch,ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘) ans=ans*10+ch-‘0‘,ch=getchar(); if(last==‘-‘) ans=-ans; return ans; } int n,star,maxl; int a[105]; int f[55][1010]; int ans=-1; int dfs(int pos,int level) { if(pos>n) return ans=max(ans,level); if(f[pos][level]!=-1) return f[pos][level]; if(level+a[pos]>maxl&&level-a[pos]<0) return -1; if(level+a[pos]<=maxl&&level+a[pos]>=0) f[pos][level]=max(f[pos][level],dfs(pos+1,level+a[pos])); if(level-a[pos]<=maxl&&level-a[pos]>=0) f[pos][level]=max(f[pos][level],dfs(pos+1,level-a[pos])); return f[pos][level]; } int main() { n=read();star=read();maxl=read(); for(int i=1;i<=n;i++) a[i]=read(); memset(f,-1,sizeof(f)); dfs(1,star); printf("%d\n",ans); return 0; }
(一开始试图直接敲正解,但是只想到了01背包而不是到达型。。。)
所谓到达型, f [ i ][ j ] 表示前 i 首歌,能否到达音量 j ,bool 数组记录即可
转移的时候就转移合法音量区间的就好
初始化 由于给出开始音量,所以只有 f [ 0 ][ beginlevel ] = 1
//100 pt 01 bag #include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cmath> #include<string> #include<cstring> #include<queue> using namespace std; typedef long long ll; inline int read() { int ans=0; char last=‘ ‘,ch=getchar(); while(ch<‘0‘||ch>‘9‘) last=ch,ch=getchar(); while(ch>=‘0‘&&ch<=‘9‘) ans=ans*10+ch-‘0‘,ch=getchar(); if(last==‘-‘) ans=-ans; return ans; } int n,star,maxl; int a[105]; bool f[55][1010]; int ans=-1; int main() { n=read();star=read();maxl=read(); for(int i=1;i<=n;i++) a[i]=read(); f[0][star]=1; for(int i=1;i<=n;i++) for(int j=maxl;j>=0;j--){ if(j-a[i]>=0&&j-a[i]<=maxl) f[i][j]|=f[i-1][j-a[i]]; if(j+a[i]>=0&&j+a[i]<=maxl) f[i][j]|=f[i-1][j+a[i]]; } for(int j=0;j<=maxl;j++){ if(f[n][j]) ans=max(ans,j); } printf("%d\n",ans); return 0; }
如果你不小心 CE 了,请不要使用 begin 作为变量
标签:bag 暴搜 超过 开始 nbsp read getchar 返回 数组
原文地址:https://www.cnblogs.com/xiaoyezi-wink/p/12004639.html