1003 [USACO 2008 Jan G]Cell Phone Network 最小支配集
链接:https://ac.nowcoder.com/acm/contest/25022/1003
来源:牛客网
题目描述
Farmer John has decided to give each of his cows a cell phone in hopes to encourage their social interaction. This, however, requires him to set up cell phone towers on his N (1 ≤ N ≤ 10,000) pastures (conveniently numbered 1..N) so they can all communicate.
Exactly N-1 pairs of pastures are adjacent, and for any two pastures A and B (1 ≤ A ≤ N; 1 ≤ B ≤ N; A ≠ B) there is a sequence of adjacent pastures such that A is the first pasture in the sequence and B is the last. Farmer John can only place cell phone towers in the pastures, and each tower has enough range to provide service to the pasture it is on and all pastures adjacent to the pasture with the cell tower.
Help him determine the minimum number of towers he must install to provide cell phone service to each pasture.
Exactly N-1 pairs of pastures are adjacent, and for any two pastures A and B (1 ≤ A ≤ N; 1 ≤ B ≤ N; A ≠ B) there is a sequence of adjacent pastures such that A is the first pasture in the sequence and B is the last. Farmer John can only place cell phone towers in the pastures, and each tower has enough range to provide service to the pasture it is on and all pastures adjacent to the pasture with the cell tower.
Help him determine the minimum number of towers he must install to provide cell phone service to each pasture.
输入描述:
* Line 1: A single integer: N
* Lines 2..N: Each line specifies a pair of adjacent pastures with two space-separated integers: A and B
输出描述:
* Line 1: A single integer indicating the minimum number of towers to install
分析
最小独立集是每个边都被覆盖,最小支配集是每个节点都被覆盖。
f[i][0] 表示当前节点被选中
f[i][1] 表示被子节点覆盖
f[i][2] 表示被父节点覆盖
状态转移:
f[i][0] += Emin(f[k][0],f[k][1],f[k][2]);
f[i][2] += Emin(f[k][0],f[k][1]);
f[i][1] 要考虑被哪一个叶子节点覆盖,这要具体到每一个叶子节点的dp值大小
如果叶子节点自己被选中比被叶子节点被选中得到的数量小的话,那直接让叶子节点自己被选中就可以了。
反之如果每个叶子节点自己被自己覆盖比自己被子节点覆盖得到的数量多的话,由于当前点必须被子节点覆盖,所以必须挑一个子节点自己覆盖自己。应该挑选了自己之后和选自己子节点相比差值最小的。
f[i][1] += Emin(f[k][0],f[k][1]) + inc;
inc = max(min(f[k][0] - f[k][1]),0); 如果直接选子节点更适合那当然是0了。
//-------------------------代码---------------------------- //#define int ll const int N = 2e6+10; int ans,n,m; int f[N][3]; bool vis[N]; void dfs(int p,int fa,V<int> g[]) { int inc = inf; f[p][1] = 0; f[p][0] = 1; f[p][2] = 0; for(int i = 0;i<g[p].size();i++) { int j = g[p][i]; if(j == fa) continue; dfs(j,p,g); f[p][0] += min({f[j][0],f[j][1],f[j][2]}); f[p][2] += min(f[j][0],f[j][1]); f[p][1] += min(f[j][0],f[j][1]); inc = min(inc,f[j][0] - f[j][1]); } if(inc<0)inc = 0; f[p][1] += inc; } void solve() { cin>>n; V<int> g[n+1]; V<bool> st(n+1); fo(i,1,n-1) { int a,b;cin>>a>>b; g[b].pb(a); g[a].pb(b); } dfs(1,0,g); ans = min(f[1][0],f[1][1]); cout<<ans<<endl; } signed main(){ clapping();TLE; // int t;cin>>t;while(t -- ) solve(); // {solve(); } return 0; } /*样例区 */ //------------------------------------------------------------