UVA 1380 A Scheduling Problem

题目链接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=4126

$LRJ$紫书例题$9-26$

 

题目大意:

给定一颗树 有些边已经标好方向 现在要给其余的边标上方向 使得最长的有向链最短

$HIT:$ 题目额外给了一个结论 假设已经确定方向的边所能得到的最长链为$k$ 最后的最长链一定$k$ 或$k + 1$

 

不知道是自己太久没有写树形$DP$还是这题的确比较麻烦 花了好久才折腾出来

首先 利用题目给的结论 我们实际上只需要解决以下这个几乎等价的问题

判断所给的树是否可以构造出最长链不超过$k$的方案

如果是的 那么最长链就是$k$否则为$k + 1$


对于这个可行解问题 我们可以这样考虑

对于每颗子树的最长链 它要么经过这颗子树的根节点 要么在这个根节点的某个儿子所对应的子树中

因此只需递归地去检验每颗子树是否合法即可

我们可以建立三个数组 $f[x][y]$ $up[x]$ $down[x]$

$f[x][y]$代表 到达该根节点$x$的向上的最长链最小值为$y$时向下的最长链最小值为多少

$up[x]$ $down[x]$分别代表该根节点向上/下的最长链的最小值

然后由于数据范围比较小 所以可以直接用这种$O(n^2)$的方法轻松解决

 

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 const int N = 210, E = N << 1;
  4 int firste[N], nexte[E], v[E], w[E];
  5 int n, e, ans;
  6 void build(int x, int y, int z)
  7 {
  8     nexte[++e] = firste[x];
  9     firste[x] = e;
 10     v[e] = y;
 11     w[e] = z;
 12 }
 13 void init(int uu)
 14 {
 15     int vv;
 16     char ch;
 17     n = 0;
 18     e = 1;
 19     memset(firste, 0, sizeof firste);
 20     ans = 0;
 21     do
 22     {
 23         n = max(n, uu);
 24         while(scanf("%d%c", &vv, &ch), vv)
 25         {
 26             n = max(n, vv);
 27             if(ch == 'd')
 28             {
 29                 build(uu, vv, 1);
 30                 build(vv, uu, 0);
 31             }
 32             else if(ch == 'u')
 33             {
 34                 build(uu, vv, 0);
 35                 build(vv, uu, 1);
 36             }
 37             else
 38             {
 39                 build(uu, vv, 0);
 40                 build(vv, uu, 0);
 41             }
 42         }
 43     }while(scanf("%d", &uu), uu);
 44 }
 45 void dfs0(int u, int fa, int dist)
 46 {
 47     ans = max(ans, dist);
 48     for(int p = firste[u]; p; p = nexte[p])
 49         if(w[p] && v[p] != fa)
 50             dfs0(v[p], u, dist + 1);
 51 }
 52 int f[N][N], up[N], down[N];
 53 bool dfs(int u, int fa)
 54 {
 55     for(int p = firste[u]; p; p = nexte[p])
 56         if(v[p] != fa)
 57         {
 58             if(!dfs(v[p], u))
 59                 return 0;
 60             if(w[p])
 61             {
 62                 for(int i = 0; i <= min(down[v[p]], ans); ++i)
 63                     f[u][i] = ans + 1;
 64             }
 65             else if(w[p ^ 1])
 66             {
 67                 for(int i = 0; i <= ans; ++i)
 68                     f[u][i] = max(f[u][i], up[v[p]] + 1);
 69             }
 70             else
 71             {
 72                 for(int i = 0; i <= down[v[p]]; ++i)
 73                     f[u][i] = max(f[u][i], up[v[p]] + 1);
 74             }
 75         }
 76     bool re = 0;
 77     for(int i = 0; i <= ans; ++i)
 78         if(f[u][i] + i <= ans)
 79         {
 80             re = 1;
 81             down[u] = min(down[u], i);
 82             up[u] = min(up[u], f[u][i]);
 83         }
 84     return re;
 85 }
 86 int main()
 87 {
 88     int tmp;
 89     while(scanf("%d", &tmp), tmp)
 90     {
 91         init(tmp);
 92         for(int i = 1; i <= n; ++i)
 93                 dfs0(i, i, 0);
 94         memset(f, 0, sizeof f);
 95         memset(down, 0x3f, sizeof down);
 96         memset(up, 0x3f, sizeof up);
 97         if(dfs(1, 1))
 98             printf("%d\n", ans + 1);
 99         else
100             printf("%d\n", ans + 2);
101     }
102     return 0;
103 }

 

posted @ 2016-12-07 21:08  sagitta  阅读(515)  评论(0编辑  收藏  举报