背包方案-cf1650F
F. Vitaly and Advanced Useless Algorithms
题目大意:
n个任务和m种操作,每个任务有他的ddl,i操作可以花费ti时间使得ei任务完成百分之pi。问能否在所有任务的ddl前完成所有任务,若能则输出要执行哪些操作,若不能输出-1 。
思路和代码:
对于每一种任务分开考虑,做一个背包。在选择背包的时候,可以选择时间作为容量,完成度作为价值;或者完成度作为容量,时间作为价值。
因为我们需要在最短的时间李做完这件事,所以我们选择完成度为容量,时间作为价值,min的一个01背包。
然后就是01背包的方案问题。
有两种解法,法二不知道为啥RTE 了我太菜了估计没码好
法一:用一维滚动数组,在每个点下面挂一条操作序列,操作序列随着dp数组转移而转移。
法二:二维dp数组,做完后逆推,有:(dp[i][pst-a[i].p]+a[i].t==tm)的时候可以向前回溯。
void solve2(){
ll n , m ;
cin >> n >> m ;
vct<ll> ddl(n + 1 , 0) ;
rep(i , 1 , n) cin >> ddl[i] ;
vct<vct<op> > tsk(n + 1 , vct<op>(1 , {0 , 0 , 0})) ;
rep(i , 1 , m){
ll e , t , p ;
cin >> e >> t >> p ;
tsk[e].pb({i , t , p}) ;
}
ll cur = 0 ;
vct<ll> ans ;
rep(e , 1 , n){
vct<ll> dp(120 , INF) ;
vct<vct<ll> > pre(120) ;//操作序列
dp[0] = 0 ;
ll num = tsk[e].size() - 1 ;
rep(i , 1 , num){
ll pp = tsk[e][i].p ;
ll tt = tsk[e][i].t ;
drep(j , 0 , 100){//枚举pst,j代表转移前的点
ll nj = min(1LL * 100 , j + pp) ;//nj代表转移到的点
if(dp[nj] > dp[j] + tt ){
dp[nj] = dp[j] + tt ;
pre[nj] = pre[j] ;//操作序列转移
pre[nj].pb(tsk[e][i].idx) ;
}
}
}
cur += dp[100] ;//若到不了dp[100]为INF,也是会退出的
if(cur > ddl[e]){
cout << "-1\n" ;
return ;
}
for(auto x : pre[100]) ans.pb(x) ;
}
cout << ans.size() << "\n" ;
for(ll x : ans) cout << x << " " ; cout << "\n" ;
}
小结:
比较标准的01背包方案问题。

浙公网安备 33010602011771号