题意:给一个无向无环图(n<1000),在尽量少的节点上放灯,使得所有边都被照亮,灯可以照亮相邻的边,在灯数最小的前提下,使得被两盏灯照亮的边最多,输出灯数以及被两盏灯照亮的边数,及剩下的边数
题解:树形dp,树上的优化,灯选或不选dp[i][0]和dp[i][1],主要的问题在于多个限制条件,这里就有一个小技巧,可以把两个限制条件变为一个数,b = M*a+c,a是灯的数量,c是一盏灯的数量,M是一个很大的数,那么这样a就占据主导作用,接下来就是树形dp具体看代码,注意初始化
#include <bits/stdc++.h> #define ll long long #define maxn 1100 #define M 2000 using namespace std; vector<int >G[maxn]; int dp[maxn][2], dir[maxn]; int dfs(int x){ dir[x] = 1; dp[x][0] = 0; dp[x][1] = M; for(int i=0;i<G[x].size();i++){ int u = G[x][i]; if(dir[u]) continue; dfs(u); dp[x][1] += min(dp[u][1], dp[u][0]+1); dp[x][0] += dp[u][1]+1; } return min(dp[x][0], dp[x][1]); } int main(){ int T, n, m, a, b, ans; scanf("%d", &T); while(T--){ memset(dir, 0, sizeof(dir)); ans = 0; scanf("%d%d", &n, &m); for(int i=0;i<n;i++) G[i].clear(); for(int i=0;i<m;i++){ scanf("%d%d", &a, &b); G[a].push_back(b); G[b].push_back(a); } for(int i=0;i<n;i++) if(!dir[i]) ans += dfs(i); printf("%d %d %d ", ans/M, m-ans%M, ans%M); } return 0; }