2011分区联赛模拟试题 电子眼【树形DP】

原题链接传送门

D e s c r i p t i o n Description Description

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

I n p u t Input Input

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

O u t p u t Output Output

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

S a m p l e   I n p u t Sample ~Input Sample Input

3
1 2
1 3

S a m p l e   O u t p u t Sample ~Output Sample Output

1

H i n t Hint Hint
30% N<=100
50% N<=1000
100% N<=100000


树型动规
一看数据范围十万
邻接矩阵显然原地爆炸。
在这里插入图片描述
这里需要用到邻接表(链式前向星)
但是我不会啊!!!
在这里插入图片述
那就学呗

图或树的邻接表

利用链式储存结构。
对于每一个顶点,开一条链,
依次存储以该点为起点的边。
下面的代码用e数组储存边的信息,
head[i]储存i这个顶点对应的链的起始位置。
同时
e
中的next域使所有起始点为i的边连成一条链。

void add(int x,int y)
{
	e[++tot].x=x;
	e[tot].to=y;
	e[tot].next=head[x];
	head[x]=tot;
}

会了邻接表就好办啦!!!

动态转移方程:

如果当前路口装电子眼,那么和它相连的路口可装可不装,则
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]

程序:

#include
#include
using namespace std;
const int N=100100;
int n,x,y,head[1001000],tot,f[1001000][2];
int bj[1001000];
struct NOTE
{
	int x,to,next;
}e[N*2];
void ljb(int x,int y)
{
	e[++tot].x=x;
	e[tot].to=y;
	e[tot].next=head[x];
	head[x]=tot;
}
void dp(int now)
{
    f[now][0]=0;
    f[now][1]=1;
    bj[now]=1;
	for(int i=head[now]; i!=0; i=e[i].next)
	 {
	 	if(bj[e[i].to]==1)
	 	  continue;
	 	bj[e[i].to]=1;
	 	dp(e[i].to);
	 	f[now][0]=f[now][0]+f[e[i].to][1];
	 	f[now][1]=min(f[e[i].to][0],f[e[i].to][1])+f[now][1];
	 }
}
int main()
{
	cin>>n;
	for(int i=1; i<=n-1; i++)
	 {
	 	scanf("%d%d",&x,&y); 
	 	ljb(x,y);
	 	ljb(y,x);
	 }
	dp(1);
	cout<<min(f[1][0],f[1][1]);
	return 0;
}

你可能感兴趣的:(题解(较高质量),dp,#,树形DP)