【题意】 有n<=200个恰好需要一天完成的任务,要求用最少的时间完成所有任务。任务可以同时完成。但是有一些约束,分有向和无向两种,其中A-->B表示A必须在B前面完成,而A--B表示A和B不能在同一天完成。

题解:最具体的题解在紫书上。。。

如果树上的所有边都是有向边,那么答案就是最长链上的点数。

这个显然。。因为A-->B--->C---->D就最少需要四天。。

这样,原问题转化为:将树上所有的无向边定向,使得树上的最长链最短。

最长链最短——二分答案。

现在问题再次转化:给定一个x,判断是否可以给无向边定向,使得最长链的点数<=x。

设定f[i]表示以i为根的子树全部定向后,最长链点数不超过x的前提下,后代到i的最长链的最小值。g[i]相反(i到后代)。

设y为i的某个孩子。

转化无向边的过程分为两种情况:

a. 如果一个子树中不存在无向边,则经过子树的根结点的最长有向路结点数为f+g+1。

b. 如果一个结点a的子结点存在无向边,则我们先递归求出所有a的子结点的f和g,然后暴力枚举将所有无向边转化为上行/下行有向边,对于每一种枚举,按照上面不存在无向边时的方法,求出f,  g和f+g+1,检查是否大于k。枚举的过程中,记下所有成功的枚举中最小的f和g,把它们和原本就是有向边子结点的最小的f和g比较,取较大值。(f和g本身是最长路的长度,这里要取的是不同成功的枚举情况下,遇到的最小的f和g。

如何给边定向呢?

但是如果我们完全枚举无向边的转换方法,则复杂度为O(2^n),n为子结点中无向边的数量。这里有一个非常棒的优化:

求出所有子结点的f和g之后,把无向边的f和g值存到一个数组中,按照f值排序。

之后我们从第一位开始考虑,将无向边换为下行有向边,考虑到第p位的时候,我们可以将前p-1位的无向边一并换为下行有向边。因为第p位的f值大于前p-1位无向边的f值,将前p-1位同时换为下行有向边,整个树的f值不会变(f为最长路的长度,而排序后,前p-1位形成的路都不会比第p位长),而g值有可能变小。这时,我们找出第p+1位到第n位中最大的g值,求出f+g+1,检查是否小于等于k即可。一旦有某一个p满足了要求就可以得出结果并终止枚举。复杂度为线性。

也就是说,我们只需要枚举p,把f值前小的全部定向为y-->i。

求g的过程相同,按照g值排序、枚举即可。

为什么取的是不同情况下遇到的最小的f和g呢?

因为对于以后要用到f[i]和g[i]的点,必定是i的父亲,它每次只用到f[i]或g[i]。

但是对于根节点而言,它的最长链是f[i]+g[i],这里的f[i]和g[i]取了不同的情况,所以我们在求f[i]、g[i]的时候就看ff+gg+1是否<=lim,是的话才更新。也就是说,如果没有一种方案满足,f[i]和g[i]都是INF。

所以最后判断是否可行只需要看根节点的f[i]或g[i]是否<INF即可。

  1 #include<cstdio>
  2 #include<cstdlib>
  3 #include<cstring>
  4 #include<iostream>
  5 #include<algorithm>
  6 using namespace std;
  7
  8 const int N=210,INF=(int)1e9;
  9 int n,len,tl,f[N],g[N],first[N];
 10 struct node{
 11     int x,y,next,tmp;
 12     bool bk;
 13 }a[N];
 14 struct point{
 15     int d,id;
 16 }tf[N],tg[N];
 17
 18 int maxx(int x,int y){return x>y ? x:y;}
 19 int minn(int x,int y){return x<y ? x:y;}
 20
 21 void ins(int x,int y,int tmp)
 22 {
 23     a[++len].x=x;a[len].y=y;a[len].tmp=tmp;a[len].bk=0;
 24     a[len].next=first[x];first[x]=len;
 25 }
 26
 27 bool cmp(point x,point y){return x.d<y.d;}
 28
 29 void dp(int x,int lim)
 30 {
 31     for(int i=first[x];i;i=a[i].next) dp(a[i].y,lim);
 32     tl=0;
 33     for(int i=first[x];i;i=a[i].next)
 34     {
 35         int y=a[i].y;
 36         if(a[i].tmp==2)
 37         {
 38             tl++;
 39             tf[tl].d=f[y];tf[tl].id=i;
 40             tg[tl].d=g[y];tg[tl].id=i;
 41         }
 42     }
 43     sort(tf+1,tf+1+tl,cmp);
 44     sort(tg+1,tg+1+tl,cmp);
 45     if(tl==0)
 46     {
 47         f[x]=0;g[x]=0;
 48         for(int i=first[x];i;i=a[i].next)
 49         {
 50             int y=a[i].y;
 51             if(a[i].tmp==1) f[x]=maxx(f[x],f[y]+1);
 52             if(a[i].tmp==0) g[x]=maxx(g[x],g[y]+1);
 53             if(f[x]+g[x]+1>lim) {f[x]=INF,g[x]=INF;break;}
 54         }
 55         if(!first[x]) f[x]=g[x]=INF;//debug
 56     }
 57     else
 58     {
 59         //find_f
 60         f[x]=INF;g[x]=INF;
 61         int ff,gg;
 62         for(int k=0;k<=tl;k++)
 63         {
 64             ff=0;gg=0;
 65             if(k>0) a[tf[k].id].bk=1;
 66             for(int i=first[x];i;i=a[i].next)
 67             {
 68                 int y=a[i].y;
 69                 if(a[i].tmp==1 || (a[i].tmp==2 && a[i].bk==1)) ff=maxx(ff,f[y]+1);
 70                 if(a[i].tmp==0 || (a[i].tmp==2 && a[i].bk==0)) gg=maxx(gg,g[y]+1);
 71             }
 72             if(ff+gg+1<=lim) f[x]=minn(f[x],ff);
 73         }
 74         for(int k=1;k<=tl;k++) a[tf[k].id].bk=0;
 75
 76
 77         for(int k=0;k<=tl;k++)
 78         {
 79             ff=0;gg=0;
 80             if(k>0) a[tg[k].id].bk=1;
 81             for(int i=first[x];i;i=a[i].next)
 82             {
 83                 int y=a[i].y;
 84                 if(a[i].tmp==1 || (a[i].tmp==2 && a[i].bk==0)) ff=maxx(ff,f[y]+1);
 85                 if(a[i].tmp==0 || (a[i].tmp==2 && a[i].bk==1)) gg=maxx(gg,g[y]+1);
 86             }
 87             if(ff+gg+1<=lim) g[x]=minn(g[x],gg);
 88         }
 89         for(int k=1;k<=tl;k++) a[tg[k].id].bk=0;
 90     }
 91     // printf("f %d = %d   g %d = %d\n",x,f[x],x,g[x]);
 92 }
 93
 94 bool check(int lim)
 95 {
 96     // printf("lim = %d\n",lim);
 97     dp(1,lim);
 98     return (f[1]<INF);
 99 }
100
101 int main()
102 {
103     freopen("a.in","r",stdin);
104     int n,y;
105     char ch;
106     while(1)
107     {
108         n=0;
109         len=0;
110         memset(first,0,sizeof(first));
111         while(1)
112         {
113             int x;
114             scanf("%d",&x);
115             if(x==0) break;
116             n=maxx(n,x);
117             while(1)
118             {
119                 scanf("%d%c",&y,&ch);
120                 n=maxx(n,y);
121                 if(y==0) break;
122                 if(ch=='d') ins(x,y,0);
123                 else if(ch=='u') ins(x,y,1);
124                 else ins(x,y,2);
125             }
126         }
127         if(n==0) break;
128         int l=0,r=n,mid;//debug 是n而不是n-1
129         while(l<r)
130         {
131             mid=(l+r)/2;
132             if(check(mid)) r=mid;
133             else l=mid+1;
134         }
135         printf("%d\n",l);
136     }
137     return 0;
138 }

转载于:https://www.cnblogs.com/KonjakJuruo/p/5969831.html

【uva1380 - 一个调度问题】思路题+树形dp相关推荐

  1. [蓝桥杯][2015年第六届真题]生命之树(树形dp)

    题目描述 在X森林里,上帝创建了生命之树. 他给每棵树的每个节点(叶子也称为一个节点)上,都标了一个整数,代表这个点的和谐值. 上帝要在这棵树内选出一个非空节点集S,使得对于S中的任意两个点a,b,都 ...

  2. Tree Cutting POJ - 2378(树形DP)

    题意:有n个谷仓有n-1条路连接,问最少删除哪几个点才能使得删除点后得到的连通图的加点数不大于n/2. 分析:求树的重心的变形题,poj3107的简单版,一遍dfs从叶子到根转移找出找到以每个节点为根 ...

  3. 【CF1646D】D. Weight the Tree(树形dp、贪心)

    加权树 题意: 给定一颗树,让你给树上的点赋予权值.定义一个点的权值等于其所有相邻节点的权重之和时,这个点就是 good. 你需要找到一种赋值方法,使得树中 good 点数最多,同时所有顶点的权重总和 ...

  4. 树形DP总结,持续更新

    自己做了动态规划的题目已经有了一个月,但是成效甚微,所以来总结一下动态规划,希望自己能够温故知新.这个博客是关于树形dp的,动态规划的一类题目. 首先从最简单的树形DP入手,树形DP顾名思义就是一棵树 ...

  5. 1579: 【例 5】皇宫看守(最小支配集——贪心求解/树形DP)

    [题目描述] 太平王世子事件后,陆小凤成了皇上特聘的御前一品侍卫. 皇宫以午门为起点,直到后宫嫔妃们的寝宫,呈一棵树的形状,某些宫殿间可以互相望见.大内保卫森严,三步一岗,五步一哨,每个宫殿都要有人全 ...

  6. HDU - 1520 Anniversary party [树形dp]

    Anniversary party 时限:1000ms Problem Description There is going to be a party to celebrate the 80-th ...

  7. hdu1561 树形dp

    题意:       给你n个东西,每个东西有自己的价值,让你从里面最多取出m个物品,问最大的价值,有的物品有限制,就是必须先取出某个物品后才能取出这个物品. 思路:       树形dp,应该是树形的 ...

  8. hdu4126(MST + 树形dp

    题意:       这个题目和hdu4756差不多,是给你一个图,然后是q次改变边的权值,权值只增不减,最后问你每次改变之后的最小树的平均值是多少. 思路:(prim+树形dp)       先跑一边 ...

  9. 【题解】hdu 3586 Information Disturbing 二分 树形dp

    题目描述 Information Disturbing Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Jav ...

最新文章

  1. 重大BUG:你的淘宝双十一订单可能多付钱了!
  2. 嵌入层 tf.keras.layers.Embedding() 介绍【TensorFlow2入门手册】
  3. 数据挖掘相关知识介绍
  4. SpringBoot2.1.5(6)----中文配置指南
  5. python字符串一(字符串的书写输入输出)
  6. [区块链] 带你进入Bitcoin开发 - 环境搭建
  7. 笔记︱利用python + flask制作一个简易本地restful API
  8. 让一个视图对触摸事件作出响应, 需要实现的方法
  9. AB1562_UT软件分辨真假洛达1562A,洛达1562a怎么鉴别?
  10. 概率论与数理统计思维导图_“我更强调统计学的思维”——专访北京师范大学未来教育学院李勇教授...
  11. “牙医”教你用450行Go代码自制编程语言 | Gopher Daily (2021.01.15) ʕ◔ϖ◔ʔ
  12. 超全的人脸识别数据集汇总
  13. 20+非常棒的Photoshop卡通设计教程
  14. YGEV型系列电磁式明渠流速仪
  15. webservice学习wsdl解读(2)
  16. 深度学习是当前很热门的机器学习算法。在深度学习中,涉及到大量矩阵相乘,
  17. 优化计算机 教学设计,信息技术优化教学设计
  18. windows开机启动
  19. AWS 区域(Region)
  20. Java雷电游戏要准备什么_Java 雷电游戏(未完成)

热门文章

  1. cgi+bin+php,crontab+php-cgi/php 定时执行PHP脚本
  2. java label覆盖_java – 将JLabel置于JLabel之上,其中包含图像
  3. java 安卓界面 可视化_Monkey可视化工具开发(android篇)
  4. c语言ascii码表_新手小白整理C语言笔记备忘,带你十分钟理解C语言
  5. mysql 5.5 重新编译_源码编译mysql5.5过程记录
  6. html 轮播 平移,网站轮播图的实现-平移版
  7. maven 加入第三方库_关于maven,你还要翻阅多少资料才能整理出这一份完整文档...
  8. hbase集群之间数据迁移_hbase数据迁移到另一集群上
  9. python三维数据转换成二维_5大Python可视化库到底选哪个好?一篇文章搞定从选库到教学...
  10. flash写保护原理_为什么固态会掉盘?著名的30分钟大法修复是什么原理?