P1273 有线电视网
P1273 有线电视网 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
令dp[x][i]为第i个节点,转移x个客户的最少费用
转移:dp[x][i]=max(dp[x][i],dp[x][i-k]+dp[v][k]-val[x][v]); 背包树形DP
但是这题获取最重要的便是,树形dp的转移for循环能优化就优化,这即能缩短时间,还能排除一些不符合条件的dp状态
for(int j=m;j;j--) for(int k=1;k<=j;k++) dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[v][k]-val[x][v]);
例如上面的便会TLE。
就是我们加一个num[x],便是x节点的子树包含了num[x]个客户。
for(auto v:g[x]) for(int j=num[x];j;j--) for(int k=1;k<=j;k++) dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[v][k]-val[x][v]);
这样就能大大的优化时间。
Code:
#include<bits/stdc++.h> using namespace std; #define ll long long #define mp make_pair #define pb push_back #define popb pop_back #define fi first #define se second const int N=3e3+10; //const int M=; const int inf=0x3f3f3f3f; //const ll INF=0x3ffffffffffff; int T,n,m,val[N][N],a[N],dp[N][N],num[N]; vector<int> g[N]; inline int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*f; } void dfs(int x) { if(!g[x].size()) dp[x][1]=a[x],num[x]=1; for(auto v:g[x]) { dfs(v); num[x]+=num[v]; } for(auto v:g[x]) for(int j=num[x];j;j--) for(int k=1;k<=j;k++) dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[v][k]-val[x][v]); } int main() { // freopen("","r",stdin); // freopen("","w",stdout); n=read(),m=read(); for(int i=1;i<=n-m;i++) { int k=read(); for(int j=1;j<=k;j++) { int u=read(); val[i][u]=val[u][i]=read(); g[i].pb(u); } } for(int i=n-m+1;i<=n;i++) a[i]=read(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) dp[i][j]=-inf; dfs(1); int ans=0; for(int i=1;i<=m;i++) if(dp[1][i]>=0) ans=i; printf("%d",ans); return 0; }