题目传送门
非常神奇的一道题。
我们不考虑交换操作,相反,我们去考虑把多少个 \(0\) 的位置变为 \(1\),同时我们记录选了多少个黑点,如果跟原来黑点数量相同即是合法。
此时我们可以发现一个神奇的性质对于 \(u\) 的儿子 \(v\),如果覆盖 \(u\) 的节点不覆盖 \(v\),那么覆盖 \(v\) 的节点在 \(v\) 的子树内的时候最优,因为不在的话会让覆盖 \(u\) 的节点变成覆盖 \(v\) 的节点。
所以我们可以考虑设 \(f_{u,i,k}\) 表示以 \(u\) 为根的子树,选了 \(i\) 个黑点,覆盖 \(u\) 的节点是 \(k\) 的最小需要把多少个白点变为黑点,然后我们可以树上背包。复杂度显然 \(\Theta(n^3)\)。
#include <bits/stdc++.h> using namespace std; #define Int register int #define MAXN 505 #define sh short template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} template <typename T> inline void chkmax (T &a,T b){a = max (a,b);} template <typename T> inline void chkmin (T &a,T b){a = min (a,b);} #define pii pair<int,int> #define se second #define fi first vector <pii> g[MAXN]; int n,X,tot,col[MAXN]; sh f[MAXN][MAXN][MAXN],h[MAXN][MAXN],miv[MAXN][MAXN]; int ind,tur[MAXN],dfn[MAXN],siz[MAXN]; void dfs (int u,int fa){ dfn[u] = ++ ind,tur[ind] = u; for (pii it : g[u]){ int v = it.fi; if (v ^ fa) dfs (v,u); } } void getdis (int u,int rt,int fa,int dis){ if (u == rt) f[u][1][dfn[u]] = 1 ^ col[u]; else f[rt][0][dfn[u]] = 0; for (pii it : g[u]){ int v = it.fi,w = it.se; if (v != fa && dis + w <= X) getdis (v,rt,u,dis + w); } } void dfs1 (int u,int fa){ siz[u] = 1; for (pii it : g[u]){ int v = it.fi; if (v == fa) continue; dfs1 (v,u); for (Int i = 0;i <= siz[u];++ i) for (Int t = 1;t <= n;++ t) h[i][t] = f[u][i][t],f[u][i][t] = 0x3f3f; for (Int i = 0;i <= siz[u];++ i) for (Int t = 1;t <= n;++ t){ for (Int j = 0;j <= siz[v] && i + j <= tot;++ j){ chkmin (f[u][i + j][t],(sh)(h[i][t] + f[v][j][t])); if (t < dfn[v] || t >= dfn[v] + siz[v]) chkmin (f[u][i + j][t],(sh)(h[i][t] + miv[v][j])); } } siz[u] += siz[v]; } for (Int i = 0;i <= siz[u];++ i){ miv[u][i] = 0x3f3f; for (Int k = dfn[u];k <= dfn[u] + siz[u] - 1;++ k) chkmin (miv[u][i],f[u][i][k]); } } signed main(){ read (n,X); for (Int x = 1;x <= n;++ x) read (col[x]),tot += col[x]; for (Int i = 2,u,v,w;i <= n;++ i) read (u,v,w),g[u].push_back ({v,w}),g[v].push_back ({u,w}); dfs (1,0),memset (f,0x3f,sizeof (f)); for (Int u = 1;u <= n;++ u) getdis (u,u,u,0); dfs1 (1,0);sh ans = n + 1; for (Int i = 0;i <= tot;++ i) for (Int j = 1;j <= n;++ j) chkmin (ans,f[1][i][j]); write (ans == n + 1 ? -1 : ans),putchar ('\n'); return 0; }