[USACO08JAN]Cell Phone Network G 树形dp
Posted 昵称很长很长真是太好了
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[USACO08JAN]Cell Phone Network G 树形dp相关的知识,希望对你有一定的参考价值。
题意:
John想让他的所有牛用上手机以便相互交流,他需要建立几座信号塔在N块草地中。已知与信号塔相邻的草地能收到信号。给你N-1个草地(A,B)的相邻关系,问:最少需要建多少个信号塔能实现所有草地都有信号。
思路:
开始思考的是使用dp[x][1/0]来表示结点是否有保安来解决这个问题。
但是细想了一下,父亲结点也会影响改结点的状态转移过程,所以两个结点肯定是不可以的。
用
d
p
[
x
]
[
0
/
1
/
2
]
dp[x][0/1/2]
dp[x][0/1/2]来表示x结点被自己/儿子/父亲染色的最小染色数。
很容易就可以写出
d
p
[
x
]
[
0
]
d
p
[
x
]
[
2
]
dp[x][0] dp[x][2]
dp[x][0]dp[x][2]的转移方程
d
p
[
x
]
[
0
]
+
=
m
i
n
(
d
p
[
i
]
[
0
]
,
d
p
[
i
]
[
1
]
,
d
p
[
i
]
[
2
]
)
;
dp[x][0]+=min(dp[i][0],dp[i][1],dp[i][2]);
dp[x][0]+=min(dp[i][0],dp[i][1],dp[i][2]); //
i
i
i是
x
x
x的孩子结点
d
p
[
x
]
[
2
]
+
=
m
i
n
(
d
p
[
i
]
[
0
]
,
d
p
[
i
]
[
1
]
)
dp[x][2]+=min(dp[i][0],dp[i][1])
dp[x][2]+=min(dp[i][0],dp[i][1])
但是dp[x][1]似乎不是那么好转移,因为只要他有一个孩子染了色,就可以。
所以我们想,只要在保证他最少有一个孩子被染了色的情况下进行
d
p
[
x
]
[
1
]
+
=
m
i
n
(
d
p
[
i
]
[
0
]
,
d
p
[
i
]
[
1
]
)
dp[x][1]+=min(dp[i][0],dp[i][1])
dp[x][1]+=min(dp[i][0],dp[i][1])转移不就可以了。
详情见代码注释。
代码:
//#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=2e5+10;
#define endl '\\n'
vector<int> edge[maxn];
int dp[maxn][3];
void dfs(int x,int fa){
int tot=0;dp[x][0]=1;
int len=edge[x].size();
for(auto i:edge[x]){
if(i==fa) continue;
dfs(i,x);
dp[x][0]+=min(dp[i][0],min(dp[i][1],dp[i][2]));
dp[x][2]+=min(dp[i][0],dp[i][1]);
if(dp[i][0]>dp[i][1]&&tot<len-2){
//至少要保证有一个孩子染色了,并且父亲也连接着这个节点,
//所以小于len-2
dp[x][1]+=dp[i][1];tot++;
//tot记录当前选择了几个没有被染色的孩子结点
//要保证数量小于len-2
}
else dp[x][1]+=dp[i][0];
}
if(edge[x].size()==1&&x!=1) dp[x][1]=1e9;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
for(int i=0;i<n-1;i++){
int x,y;
cin>>x>>y;
edge[x].push_back(y);
edge[y].push_back(x);
}
dfs(1,0);
cout<<min(dp[1][0],dp[1][1])<<endl;
}
以上是关于[USACO08JAN]Cell Phone Network G 树形dp的主要内容,如果未能解决你的问题,请参考以下文章
洛谷 P1948 [USACO08JAN]电话线Telephone Lines