9/5 二维费用背包+基环树+01变型背包
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了9/5 二维费用背包+基环树+01变型背包相关的知识,希望对你有一定的参考价值。
二维费用背包
int n,V,M,v[N],w[N],val[N],f[N][N];
void solve()
cin>>n>>V>>M;
for(int i=1;i<=n;i++)
cin>>v[i]>>w[i]>>val[i];
for(int i=1;i<=n;i++)
for(int j=V;j>=v[i];j--)
for(int k=M;k>=w[i];k--)
f[j][k]=max(f[j][k],f[j-v[i]][k-w[i]]+val[i]);
cout<<f[V][M]<<endl;
基环树
定义:基环树可看作是比树多了一条边,从而形成一个环。基环树可看作是以环点为根的一颗颗子树构成。
思路:
1.深搜找环。
2.断环成树,对树深搜计算。
断边技巧:标记端点或标记边
预备知识:树形dp
P2607 [ZJOI2008] 骑士
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=1e6+5;;
const int inf=1e18;
const int mod=19980829;
int n,cnt,head[N],f[N][2],a[N],r1,r2,sum;
bool vis[N];
struct node
int to,nxt,w;
e[N];
void add(int from,int to)
e[++cnt].to=to;
//e[cnt].w=w;
e[cnt].nxt=head[from];
head[from]=cnt;
void fd(int u,int rt)
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt)
int v=e[i].to;
if(v==rt)
r1=u,r2=v;return;
if(vis[v]) continue;
fd(v,rt);
int dfs(int u,int rt)
f[u][0]=0,f[u][1]=a[u];
for(int i=head[u];i;i=e[i].nxt)
int v=e[i].to;
if(v==rt) continue;
dfs(v,rt);
f[u][0]+=max(f[v][0],f[v][1]);
f[u][1]+=f[v][0];
return f[u][0];
void solve()
cin>>n;
for(int i=1;i<=n;i++)
int u;cin>>a[i]>>u;
add(u,i); //一个人可被多个人讨厌
for(int i=1;i<=n;i++)
if(!vis[i])
r1=r2=0;
fd(i,i);
if(r1)
sum+=max(dfs(r1,r1),dfs(r2,r2));
cout<<sum<<endl;
signed main()
//ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
P1453 城市环路
基环树+树形dp(类似没有上司的舞会)
本题只存在一个基环树,而骑士那题可能存在基环树森林
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=2e5+5;;
const int inf=1e18;
const int mod=19980829;
int n,cnt,head[N],f[N][2],a[N],r1,r2,ans,flag;
double k;
bool vis[N];
struct node
int to,nxt,w;
e[N];
void add(int from,int to)
e[++cnt].to=to;
//e[cnt].w=w;
e[cnt].nxt=head[from];
head[from]=cnt;
int dfs(int u,int pre,int rt)
f[u][0]=0,f[u][1]=a[u];
for(int i=head[u];i;i=e[i].nxt)
int v=e[i].to;
if(v==pre||v==rt) continue;
dfs(v,u,rt);
f[u][0]+=max(f[v][0],f[v][1]);
f[u][1]+=f[v][0];
return f[u][0];
void fd(int u,int pre)
if(flag) return;
if(!vis[u]) vis[u]=1;
for(int i=head[u];i;i=e[i].nxt)
int v=e[i].to;
if(v==pre) continue;
if(!vis[v]) fd(v,u);
else
flag=1;
int mx1=dfs(u,v,u);
int mx2=dfs(v,u,v);
ans=max(mx1,mx2);
void solve()
cin>>n;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
int u,v;cin>>u>>v;
u++,v++;
add(u,v),add(v,u);
cin>>k;
fd(1,1);
double sum=ans*k;
printf("%.1lf\\n",sum);
signed main()
//ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
另一个写法,大同小异:
void fd(int u,int pre)
if(flag)
return;
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt)
int v=e[i].to;
if(v==pre) continue;
if(vis[v])
flag=1;
r1=u,r2=v;return;
fd(v,u);
int dfs(int u,int pre,int rt)
f[u][0]=0,f[u][1]=a[u];
for(int i=head[u];i;i=e[i].nxt)
int v=e[i].to;
if(v==pre||v==rt) continue;
dfs(v,u,rt);
f[u][0]+=max(f[v][0],f[v][1]);
f[u][1]+=f[v][0];
return f[u][0];
P1417 烹调方案
化简公式,对食物进行排序。由于美味值会衰减,因此并非越靠后要好,所以要对所有f[1~t]进行枚举取最大值。
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=2e5+5;;
const int inf=1e18;
const int mod=19980829;
int t,n,f[N],ans;
struct node
int a,b,c;
e[N];
bool cmp(node x,node y)
return x.b*y.c>y.b*x.c;
void solve()
cin>>t>>n;
for(int i=1;i<=n;i++) cin>>e[i].a;
for(int i=1;i<=n;i++) cin>>e[i].b;
for(int i=1;i<=n;i++) cin>>e[i].c;
sort(e+1,e+n+1,cmp);
for(int i=1;i<=n;i++)
for(int j=t;j>=e[i].c;j--)
f[j]=max(f[j],f[j-e[i].c]+e[i].a-j*e[i].b);
for(int i=1;i<=t;i++)
ans=max(ans,f[i]);
cout<<ans<<endl;
signed main()
//ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
以上是关于9/5 二维费用背包+基环树+01变型背包的主要内容,如果未能解决你的问题,请参考以下文章
[H背包] lc879. 盈利计划(二维费用背包+难题+状态定义)
洛谷 P1507 NASA的食物计划 二维费用背包+01背包