对于一条边要将其覆盖需要选这条边的父亲节点或者儿子节点其中一个即可,对于一个点的覆盖,同样可以选父亲节点或者儿子节点,但同时可以选自己这个节点。所以前者只有两种转移,后者有三种转移。
思路:
用0表示当前节点不选,那么要想覆盖这条边,儿子节点就一定要选。用1表示当前节点选,那么儿子节点就可以不选。
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
#define fi first
#define se second
const ll mod=1e9+7;
const int N=2e5+10;
#define int ll
const double eps=1e-6;
ll qpow(ll a,ll b){
ll res=1;
while(b){
if(b&1) res=(res*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return res;
}
int n;
vector<int> v[N];
int dp[N][2];
void dfs(int x,int f){
dp[x][0]=0,dp[x][1]=1;
for(auto y:v[x]){
if(y==f) continue;
dfs(y,x);
dp[x][0]+=dp[y][1];
dp[x][1]+=min(dp[y][0],dp[y][1]);
}
}
void solve(){
while(cin>>n){
for(int i=0;i<=n;i++){
v[i].clear();
}
for(int i=1;i<=n;i++){
int x,num; char t;
cin >> x >> t >> t >> num >> t;
while(num--){
int y;cin>>y;
v[x].push_back(y);
v[y].push_back(x);
}
}
dfs(0,0);
cout<<min(dp[0][0],dp[0][1])<<endl;
}
}
signed main(){
//ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
int t=1;
//cin>>t;
while (t--){
solve();
}
return 0;
}
思路:
用0表示当前节点被选,1表示任意儿子节点被选且当前节点不被选,2表示父亲节点被选且当前节点不被选。
如果是0,那么可以从儿子节点的0,1,2状态转移(转移来源要有2的话,表示当前节点一定要选,因为当前节点就是儿子节点的父亲节点)。
如果是1的话,我们要从当前节点的所有儿子节点里去找令哪些儿子节点被选。由于我们必须要一个儿子节点被选,也就是说选的是儿子节点的0状态,又由于儿子节点除了必须要选的点,其他点可以不被选,也就是1状态(父亲节点也就是当前节点不选,本身又不选,只剩1状态了),我们可以先将所有儿子节点的min(dp0,dp1)都加上,然后再判断这些min里面有没有0状态,如果有我们就不用再改变儿子节点的状态,如果没有我们要找一个儿子节点转换成0状态,也就是去找所有儿子节点里dp0-dp1最小的(因为没有一个0状态也就是说所有儿子节点的dp0都比dp1大,那么我们贪心的选需要增加的dp0-dp1最小即可)。
如果是2的话,从0,1转移,因为当前节点没有被选,也就是儿子节点的父亲节点没有被选,不能从2(父亲节点被选)转移。
代码:
# include<bits/stdc++.h>
using namespace std;
int n;
int f[10000+10][3];
vector<int> ve[10000+10];
void dfs(int x, int fa)
{
f[x][0] = 1;
f[x][1] = 0;
f[x][2] = 0;
int inc = 0x3f3f3f;
for (int i=0; i<ve[x].size(); i++)
{
int j = ve[x][i];
if (j == fa) continue;
dfs(j, x);
f[x][0] += min(f[j][1], min(f[j][0], f[j][2]));
f[x][2] += min(f[j][0], f[j][1]);
f[x][1] += min(f[j][0], f[j][1]);
inc = min(f[j][0]-f[j][1], inc);
}
if (inc<0)
inc = 0;
f[x][1] += inc;
}
int main()
{
cin>>n;
int x, y;
while (cin>>x>>y)
{
ve[x].push_back(y);
ve[y].push_back(x);
}
dfs(1, 0);
cout<<min(f[1][0], f[1][1])<<endl;
return 0;
}