【邻接表】【树状DP】2011分区联赛模拟试题 电子眼

Description

中山市石一个环境优美、气候宜人的小城市。因为城市的交通并不繁忙,市内的道路网很稀疏。准确地说,中山市有 N − 1 N-1 N1条马路和 N N N个路口,每条马路连接两个路口,每两个路口之间最多只有一条马路。作为一条交通网络,显然每两个路口之间都是可达的。为了更好地管理中山市的交通,市长决定在一些路口加装电子眼,用来随时监视路面情况。这些装在路口的电子眼能够监视所有连接到这个路口的马路。现在市长想知道最少需要在多少个路口安装电子眼才能监视所有的马路。市长已经把所有的路口都编上了 1 ~ N 1~N 1N的号码。
给你中山市的地图,你能帮忙吗?

Input

输入文件traffic.in的第1行包括一个数字 N ( 1 < = N < = 100000 ) N(1<=N<=100000) N(1<=N<=100000),表示中山市的路口数。接下来 N − 1 N-1 N1行,每行两个数字 x i x_i xi y i y_i yi,用来描述 N − 1 N-1 N1条路所连接的两个路口的编号。

Output

输出最少需要安装电子眼的数量。

Sample Input

3
1 2
1 3

Sample Output

1

数据规模
30% N < = 100 N<=100 N<=100
50% N < = 1000 N<=1000 N<=1000
100% N < = 100000 N<=100000 N<=100000


解题思路

一开始,把min打成max,调了1个h。。。woc

首先,推一道题,没有上司的晚会(请耐心看完,这题我实在不想写思路了)
f [ r o o t ] [ 1 ] f[root][1] f[root][1]为第root个路口装电子眼的最优值
  f [ r o o t ] [ 0 ] f[root][0] f[root][0]为第root个职员不装电子眼的最优值

  • 如果当前路口装电子眼,那么和它相连的路口可装可不装,则
    f [ r o o t ] [ 1 ] + = m i n ( f [ a [ i ] . t o ] [ 0 ] , f [ a [ i ] . t o ] [ 1 ] ) f[root][1]+=min(f[a[i].to][0],f[a[i].to][1]) f[root][1]+=min(f[a[i].to][0],f[a[i].to][1])
  • 如果当前路口不装电子眼,那么和它相连的路口必须装,则
    f [ r o o t ] [ 0 ] + = f [ a [ i ] . t o ] [ 1 ] f[root][0]+=f[a[i].to][1] f[root][0]+=f[a[i].to][1]

因为这题是双向的,所以如果直接走,会死循环,爆栈。用一个数组 t t t,标记这个路口走过没。


#include<iostream>
#include<cstdio>
using namespace std;
struct DT{
	int to;
	int next;
}a[200200];
int b[100100],n,num,f[100100][2],Gun=100100,t[100100];
void DP(int root){
    f[root][1]=1;//初值
    t[root]=1;//标记
	for(int i=b[root];i;i=a[i].next){
		if(!t[a[i].to]){
			DP(a[i].to);
			f[root][1]+=min(f[a[i].to][0],f[a[i].to][1]);//装	
     		f[root][0]+=f[a[i].to][1];//不装
		}
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<n;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		a[++num].to=y;
		a[num].next=b[x];
		b[x]=num;
		a[++num].to=x;
		a[num].next=b[y];
		b[y]=num;//无向图,存两条边
	}
	DP(1);
	Gun=min(f[1][1],f[1][0]);//这个Gun好像没用(???)
	printf("%d",Gun);
} 

你可能感兴趣的:(DP,树形DP)