您的位置:首页 > 其它

Luogu P2458 [SDOI2006]保安站岗【树形Dp】

2018-07-25 08:10 253 查看

题目描述

五一来临,某地下超市为了便于疏通和指挥密集的人员和车辆,以免造成超市内的混乱和拥挤,准备临时从外单位调用部分保安来维持交通秩序。

已知整个地下超市的所有通道呈一棵树的形状;某些通道之间可以互相望见。总经理要求所有通道的每个端点(树的顶点)都要有人全天候看守,在不同的通道端点安排保安所需的费用不同。

一个保安一旦站在某个通道的其中一个端点,那么他除了能看守住他所站的那个端点,也能看到这个通道的另一个端点,所以一个保安可能同时能看守住多个端点(树的结点),因此没有必要在每个通道的端点都安排保安。

编程任务:

请你帮助超市经理策划安排,在能看守全部通道端点的前提下,使得花费的经费最少。

输入输出格式

输入格式:

第1行 n,表示树中结点的数目。

第2行至第n+1行,每行描述每个通道端点的信息,依次为:该结点标号i(0<i<=n),在该结点安置保安所需的经费k(<=10000),该边的儿子数m,接下来m个数,分别是这个节点的m个儿子的标号r1,r2,...,rm。

对于一个n(0 < n <= 1500)个结点的树,结点标号在1到n之间,且标号不重复。

输出格式:

最少的经费。

如右图的输入数据示例

输出数据示例:

1 #include<cstdio>
2 #include<algorithm>
3 #include<cmath>
4
5 using namespace std;
6 typedef long long ll;
7
8 int n,tot;
9 int head[2000],f[2000][5];
10
11 struct node{
12     int to,next;
13 }edge[4000];
14
15 void add(int x,int y)
16 {
17     edge[++tot].to=y;
18     edge[tot].next=head[x];
19     head[x]=tot;
20 }
21
22 void TreeDP(int x,int fa)
23 {
24     int cha=0x7f7f7f7f,cnt=0;
25     for(int i=head[x];i;i=edge[i].next)
26     {
27         int y=edge[i].to;
28         if(y==fa) continue;
29         TreeDP(y,x);
30         f[x][0]+=min(f[y][1],f[y][2]);
31         f[x][1]+=min(min(f[y][0],f[y][1]),f[y][2]);
32         /*if(f[y][1]<f[y][2]) f[x][2]+=f[y][1],flag=true;
33         else
34         {
35             if(flag) f[x][2]+=f[y][2];
36             else
37              if(fabs(f[y][1]-f[y][2])<min_cha)
38               min_cha=fabs(f[y][1]-f[y][2]),jian=f[y][2],jia=f[y][1],f[x][2]+=f[y][2];
39              else f[x][2]+=f[y][2];
40         }
41     }
42     if(!flag) f[x][2]=f[x][2]-jian+jia;*///我写的初始版本,但是太丑了QAQ
43         if(f[y][1]<f[y][2]) cnt++;
44         else cha=min(cha,f[y][1]-f[y][2]);
45         f[x][2]+=min(f[y][1],f[y][2]);
46         }
47         if(cnt==0) f[x][2]+=cha;
48 }
49
50 int main()
51 {
52     scanf("%d",&n);
53     for(int i=1;i<=n;i++)
54     {
55         int p,k,u,m;
56         scanf("%d%d%d",&p,&k,&m);
57         f[p][1]=k;//注意这句!我被坑了好久!不是f[i][1]=k!
58         for(int i=1;i<=m;i++)
59         {
60             scanf("%d",&u);
61             add(p,u);//由于没有暗示本题有明确的父子关系,所以还是连双向边的好
62             add(u,p);
63         }
64     }
65     TreeDP(1,0);//dfs传两个参数,一个是当前节点,一个是当前节点的父节点,是个好习惯,可以在后来的判断中防止死循环以及奇怪的MLE!
66     printf("%d",min(f[1][1],f[1][2]));
67     return 0;
68 }
View Code  

小结:本题是进阶的树形dp,只要把情况仔细梳理认真分类讨论就ok了!

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: