P2224 [HNOI2001] 产品加工——奇怪的状态优化
初见想法
记
空间复杂度
初见之后的乱搞
空间开不出来,于是决定拿记搜+set乱水,但是写到一半发现记忆化加了没意义,因为事实上没有办法统计每个物品对答案的贡献
28pts的dfs:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=6e3+5;
struct item{
int t1,t2,t3;
}a[MAXN];
int n;
int dfs(int t1,int t2,int it){
if(it>n) return max(t1,t2);
int res=2e9;
if(a[it].t1) res=min(res,dfs(t1+a[it].t1,t2,it+1));
if(a[it].t2) res=min(res,dfs(t1,t2+a[it].t2,it+1));
if(a[it].t3) res=min(res,dfs(t1+a[it].t3,t2+a[it].t3,it+1));
return res;
}//
void work(){
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d%d%d",&a[i].t1,&a[i].t2,&a[i].t3);
printf("%d",dfs(0,0,1));
}//
int main(){
work();
return 0;
}
正解
既然空间不足,考虑优化状态
容易想到的是把第
但是剩下的仍然有
而且时间复杂度依旧有
那么接下来就是我看不懂但是大受震撼的优化了:
将状态由
也就是说将影响答案的两个因素之一的状态转变为维护的值了,于是在时间和空间上都压低了一维
那么原来维护的可行性也就不需要维护了,因为在这种情况下几乎必然可以通过调整各个
另:状态转移方程和滚动优化的一些细节:
- 和背包一样,枚举时间的时候要倒序
- 状态转移方程有3中来源,即
t1,t2,t3 ,但是需要注意的是当三者都无法转移时将值赋为无穷大
code:
#include <bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int MAXN=6e3+5;
struct item{
int t1,t2,t3;
}a[MAXN];
int n;
int dp[MAXN*5],ans=inf;
void work(){
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d%d%d",&a[i].t1,&a[i].t2,&a[i].t3);
memset(dp,0,sizeof(dp));
// dp[0]=0;
for(int i=1;i<=n;++i){
for(int j=n*5;j>=0;--j){
int res1=inf,res2=inf,res3=inf;
if(a[i].t1 && j>=a[i].t1) res1=dp[j-a[i].t1];
if(a[i].t2) res2=dp[j]+a[i].t2;
if(a[i].t3 && j>=a[i].t3) res3=dp[j-a[i].t3]+a[i].t3;
dp[j]=min(res1,min(res2,res3));
}
}
for(int i=0;i<=n*5;++i) ans=min(max(i,dp[i]),ans);
printf("%d",ans);
}//
int main(){
work();
return 0;
}
试图总结这种优化使用的时机
多个参数影响最终答案,难以在过程中比较
维护的东西有可以优化掉的可能性