2119.电子眼

原题链接

外网进不去

题目大意

在一个城市里,有 n ( 1 ≤ n ≤ 100000 ) n(1\le n\le 100000) n(1n100000)个路口和 n − 1 n-1 n1条马路,而且,每个路口都是互相可达的。现在,我们要在路口上装上电子眼,以监视路面情况。每个路口的电子眼都可以监视所所有与这个路口相通的道路,求最少要装多少个电子眼。

结题思路

我们可以使用树状dp来AC掉这一题。首先,先使用链式储存结构来对每一个相通的路口进行存储:

void add(int x,int y)
{
    
    
	a[++tot].x=y;
	a[tot].last=head[x];//往上一个位置链接
	head[x]=tot;//更新最后一个位置
	return;
}

由于每个路口都是互相相通的,我们需要进行两次连接:

for(int i=1;i<n;++i){
    
    
	cin>>x>>y;
	add(x,y);
	add(y,x);
}

接下来,就是dp了,我们可以开一个二维数组,分别表示当前位置放或不放电子眼。如果放,那么上一个位置,放或不放都可以,取最小值即可;如果不放,那么上一个位置必须放。所以,状态转移方程就为: 设 c h i l d 是 一 个 与 n 联 通 的 点 f = { f 1 n = f 1 n + m i n ( f 1 c h i l d , f 0 c h i l d ) f 0 n = f 0 n + f 1 c h i l d 设child是一个与n联通的点\\f=\left\{\begin{matrix}f_{1_{n}}=f_{1_{n}}+min(f_{1_{child}},f_{0_{child}})\\f_{0_{n}}=f_{0_n}+f_{1_{child}}\end{matrix}\right. childnf={ f1n=f1n+min(f1child,f0child)f0n=f0n+f1child

代码实现

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
struct node
{
    
    
	int x,last;
} a[1000010];
int head[1000010],f[2][1000010],n,x,y,tot;
bool v[1000010];
void add(int x,int y)
{
    
    
	a[++tot].x=y;
	a[tot].last=head[x];
	head[x]=tot;
	return;
}
void dp(int n)
{
    
    
	f[1][n]=1;//初始化,如果当前放的话,当前至少有一个电子眼
	f[0][n]=0;//初始化
	for(int i=head[n];i;i=a[i].last){
    
    
		if(!v[a[i].x]){
    
    //判重,防止死循环
			v[a[i].x]=true;//判重,防止死循环
			dp(a[i].x);
			f[1][n]+=min(f[1][a[i].x],f[0][a[i].x]);//动态转移方程
			f[0][n]+=f[1][a[i].x];//动态转移方程
		}
	}
	return;
}
int main()
{
    
    
	memset(f,0x7f,sizeof(f));
	cin>>n;
	for(int i=1;i<n;++i){
    
    
		cin>>x>>y;
		add(x,y);
		add(y,x);
	}
	v[1]=true;
	dp(1);
	cout<<min(f[0][1],f[1][1]);
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_41247488/article/details/121301270