NKOI 1472 警卫安排
来源:互联网 发布:花生壳域名怎么用 编辑:程序博客网 时间:2024/04/30 06:36
警卫安排
Time Limit:10000MS Memory Limit:65536K
Total Submit:34 Accepted:18
Case Time Limit:1000MS
Description
一个重要的基地被分为n个连通的区域。出于某种神秘的原因,这些区域以一个区域为核心,呈一颗树形分布。
在每个区域安排警卫所需要的费用是不同的,而每个区域的警卫都可以望见其相邻的区域,只要一个区域被一个警卫望见或者是安排有警卫,这个区域就是安全的。你的任务是:在确保所有区域都是安全的情况下,找到安排警卫的最小费用。
Input
第一行n,表示树中结点的数目。
接下来的n行描述了n个区域的信息,每一行包含的整数依次为:区域的标号i(0<i<=n),在区域i安排警卫的费用k,区域i的子结点数目m,接下来m个数为区域i的子结点编号。
Output
一行一个整数,为最小的安排费用。
Sample Input
61 30 3 2 3 42 16 2 5 63 5 04 4 05 11 06 5 0
Sample Output
25
Hint
对于所有的数据,0<n<=720。
我们可以很显然的发现这是一道树形DP
我们讨论结点i:
i不安排警卫,i被父亲望到,这时i没有安排警卫,i的儿子要么安排警卫,要么被它的后代望到。
i不安排警卫,i被儿子望到,即i的某个儿子安排了警卫,其他儿子需要安排警卫或者被它的后代望到。
i安排了警卫,i的儿子结点被i望到,可能安排警卫,可能被它的后代看到。
状态:f[i][j]表示以i为根这棵子树按排警卫所需最小费用(其中i号节点采用的是第j种监视方式)
j代表监视方式,分为0,1,2三种
f[i][0]表示在第i号节点安排一个警卫,自己望,的最小费用
f[i][1]表示由i的儿子监视第i号位置,被儿子望,的最小费用
f[i][2]表示由i的父亲监视第i号位置 ,被父亲望,的最小费用
f[i][0]= min{ f[son[1]][0] , f[son[1]][1] , f[son[1]][2] }
+min{ f[son[2]][0] , f[son[2]][1] , f[son[2]][2] }
+......
+min{ f[son[k]][0] , f[son[k]][1] , f[son[k]][2] } + cost[i]
(i的儿子数为k)
f[i][2]= min{ f[son[1]][0] , f[son[1]][1] }+min{ f[son[2]][0] , f[son[2]][1]}
+......+min{ f[son[k]][0] , f[son[k]][1] }
至于f[I][1],我们思考:
f[i][1]是在i节点,有儿子望到i的情况,而f[i][2]是在i节点,他的父节点望到他的情况
对于f[i][1],i的所有儿子中一定有一个儿子自己安排了警卫,而对于f[i][2],i的儿子除了可以靠自己安排,也可以让自己的后代安排
因此,f[i][1]与f[i][2]满足关系f[i][1]=min{f[i][2]-min(f[s][0],f[s][1])+f[s][0]}
其中s为i的儿子
最后输出答案的时候,由于根节点没有父节点,所以输出min(f[root][0],f[root][1])
#include<cstdio>#include<iostream>using namespace std;const int maxn=1500,inf=1e9;int NEXT[maxn],END[maxn],LAST[maxn],n;int cost[maxn],cnt,f[maxn][4];bool mark[maxn];void insert(int a,int b){ END[++cnt]=b; NEXT[cnt]=LAST[a]; LAST[a]=cnt; }void DP(int p){int i,j;if(LAST[p]==0)f[p][0]=cost[p];f[p][1]=inf;return;}for(i=LAST[p],j=END[i];i;i=NEXT[i],j=END[i])DP(j);f[p][0]=cost[p];f[p][1]=inf;for(i=LAST[p],j=END[i];i;i=NEXT[i],j=END[i]){f[p][0]+=min(f[j][0],min(f[j][1],f[j][2]));f[p][2]+=min(f[j][0],f[j][1]);}for(i=LAST[p],j=END[i];i;i=NEXT[i],j=END[i]) f[p][1]=min(f[p][1],f[p][2]-min(f[j][0],f[j][1])+f[j][0]);}int main(){int i,j,x,y,m,k;scanf("%d",&n);for(i=1;i<=n;i++){scanf("%d%d%d",&x,&k,&m);cost[x]=k;for(j=1;j<=m;j++){scanf("%d",&y);insert(x,y);mark[y]=1;//mark记录当前节点是不是一个子节点}}for(i=1;i<=n;i++)//找根节点 if(!mark[i]){k=i;break;}DP(k);cout<<min(f[k][0],f[k][1]);}
- NKOI 1472 警卫安排
- 警卫安排
- 警卫安排
- 警卫安排 题解
- [作业]警卫安排
- NKOI 1349 工作安排
- NKOI 1047 任务安排
- 搜索 值班警卫
- CodeCombat-辱骂警卫
- 安排
- NKOI 3659 硬币
- NKOI 1006 护卫队
- NKOI 1123 潜水员
- NKOI 1011 锁妖塔
- NKOI 1023 生命游戏
- NKOI 1036 回文词
- NKOI 1228 丛林道路
- NKOI 2202 字符串乘方
- 利用python进行数据分析-数据规整化3
- 良好的技术学习习惯
- Android 设计模式——开闭原则
- java笔记1
- Linux安装使用mongodb
- NKOI 1472 警卫安排
- 软件测试_JUnit+Ant构建自动的单元测试(1)
- 微信内置浏览器切换到公众号编辑状态的实现方法。
- stm32 Bootloader设计(YModem协议) (转载)
- Spring之aop入门实例
- Unity Shader--简介
- UIButton 控制UIImage自由改变大小
- ShareSDK实现第三方登录和分享
- android6.0 动态申请权限