1 条题解
-
0
题意:给定 个点的一棵树,要你把每条边定向(可以双向)或删除(即一共四种情况)。求是否存在一种方案,使得任意点 都恰好可达 个点。
首先我们发现一件事情:如果有边 ,无论 是几都可能删掉,否则有 ,。
考虑树形 DP, 表示点 在它的子树中可达 个点是否可能合法。
如果点 是 父亲,设辅助数组 为上一个儿子的 ,有树形背包的转移:
- 为真:,表示删除边 。
- :,表示连双向边 。
- :,表示连边 。
- :,表示连边 。
- :直接输出
NO,表示 又不能连又不能删。
时间复杂度 。 :::success[AC 代码]{open}
#include <bits/stdc++.h> #define fi first #define se second #define mid ((l+r)>>1) #define bmid ((l+r+1)>>1) using namespace std; using ll= long long; const int N=5005,H=4000005,mod=1000000007; template<typename tp> void add(tp& x,ll y) {x=(x+y)%mod;} vector<int> g[N]; int n,l[N],siz[N],dp[N][N]; void dfs(int u,int fa) { int f[N]; siz[u]=1; dp[u][1]=1; for(int& v: g[u]) if(v!=fa) { dfs(v,u); fill(f,f+N,0); for(int i=0;i<N;i++) f[i]=dp[u][i],dp[u][i]=0; for(int i=0;i<=siz[u];i++) { if(dp[v][l[v]]) dp[u][i]|=f[i]; if(l[u]==l[v]) for(int j=0;j<=siz[v];j++) dp[u][i+j]|=f[i]&dp[v][j]; else if(l[u]>l[v]) dp[u][i+l[v]]|=f[i]; else if(!dp[v][l[v]-l[u]]&&!dp[v][l[v]]) cout<<"NO",exit(0); else if(!dp[v][l[v]]) dp[u][i]|=f[i]; } siz[u]+=siz[v]; } } int main() { cin.tie(nullptr)->sync_with_stdio(false); cin>>n; for(int i=1;i<=n;i++) cin>>l[i]; for(int u,v,i=1;i<n;i++) { cin>>u>>v; g[u].push_back(v); g[v].push_back(u); } dfs(1,0); cout<<(dp[1][l[1]]?"YES":"NO"); return 0; }:::
- 1
信息
- ID
- 10207
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者