【暑假】[深入动态规划]UVa 1380 A Scheduling Problem
UVa 1380 A Scheduling Problem
题目:
http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=41557
思路:
给出一个任务调度树,单向边u->v表示u必须在v之前完成,双向边u-v表示无所谓方向。
题目给出定理,首先dfs求得忽略无向边后的最长链点数k,那么问题就是判断是否可以通过无向边定向从而使得最长链点数不超过k。用dp的判断。
设f[i]表示以i为根的子树中所有的边定向后最长链点数不超过k条件下出边中最长链的最小值,g[i]表示以i为根的子树中所有的边定向后最长链点数不超过k条件下入边中最长链的最小值(最小值是最低限度,如果最小值都不可行那么问题不可行)。
两种情况(w为子节点):
- 与w的边中没有双向边:得出w.f_max与w.g_max判断与k的大小关系 如果超过k 回值INF否则回值w.f_max与w.g_max(max代表最长链)。没有选择的情况,已经定形。
- 与w的边中有双向边:定向双向边使满足k的限定下f与g尽量小。批量定向,求解f[u]的时候,将w按照f从小到大排序,依此枚举p,对于p将p之前的定向为出边,计算f[u]。同理求解g[u]。最后判断与k的关系。根据双向边定向选择最优结果。
代码:
1 // UVa1380 A Scheduling Problem 2 // Rujia Liu 3 #include<iostream> 4 #include<string> 5 #include<cstring> 6 #include<sstream> 7 #include<vector> 8 #include<algorithm> 9 using namespace std; 10 11 const int maxn = 200 + 5; 12 const int INF = 1000000000; 13 14 struct Edge { 15 int u, v, d; // d=1 means u->v, d=2 means v->u, d=0 means u-v 16 Edge(int u=0, int v=0, int d=0):u(u),v(v),d(d){} 17 }; 18 19 vector<Edge> edges[maxn]; 20 int n, root, maxlen, f[maxn], g[maxn], have_father[maxn]; 21 22 // maximal length of a DIRECTED path starting from u 23 int dfs(int u) { 24 int ans = 0; 25 for(int i = 0; i < edges[u].size(); i++) { 26 int v = edges[u][i].v; 27 if(edges[u][i].d == 1) //u->v 28 ans = max(ans, dfs(v)+1); 29 } 30 return ans; 31 } 32 33 bool read_data() { 34 bool have_data = false; 35 int a, b; 36 n = 0; 37 for(int i = 0; i < maxn; i++) edges[i].clear(); 38 memset(have_father, 0, sizeof(have_father)); 39 40 while(cin >> a && a){ 41 string str; 42 have_data = true; 43 if(a > n) n = a; 44 while(cin >> str && str != "0"){ 45 int len = str.length(); 46 char dir = str[len-1]; 47 if(dir == 'd' || dir == 'u') str = str.substr(0, len-1); 48 stringstream ss(str); 49 ss >> b; // b is a's son 50 if(b > n) n = b; 51 have_father[b] = 1; 52 if(dir == 'd'){ 53 edges[a].push_back(Edge(a, b, 1)); // forward 54 edges[b].push_back(Edge(b, a, 2)); // backward 55 }else if(dir == 'u'){ 56 edges[a].push_back(Edge(a, b, 2)); 57 edges[b].push_back(Edge(b, a, 1)); 58 }else{ 59 edges[a].push_back(Edge(a, b, 0)); // it's a rooted tree, so we don't store edge to father 60 } 61 } 62 } 63 if(have_data) { 64 for(int i = 1; i <= n; i++) 65 if(!have_father[i] && !edges[i].empty()) { root = i; break; } 66 } 67 return have_data; 68 } 69 70 struct UndirectedSon { 71 int w, f, g; 72 UndirectedSon(int w=0, int f=0, int g=0):w(w),f(f),g(g){} 73 }; 74 75 bool cmp_f(const UndirectedSon& w1, const UndirectedSon& w2) { 76 return w1.f < w2.f; 77 } 78 79 bool cmp_g(const UndirectedSon& w1, const UndirectedSon& w2) { 80 return w1.g < w2.g; 81 } 82 83 // calculate f[i] and g[i] 84 // return true iff f[i] < INF 85 // f[i] is the minimal length of the longest "->u" path if all subtree paths have length <= maxlen 86 // g[i] is the minimal length of the longest "u->" path if all subtree paths have length <= maxlen 87 // f[i] = g[i] = INF if "all subtree paths have length <= maxlen" cannot be satisfied 88 bool dp(int i, int fa) { 89 if(edges[i].empty()) { 90 f[i] = g[i] = 0; 91 return true; 92 } 93 vector<UndirectedSon> sons; 94 int f0 = 0, g0 = 0; // f'[i] and g'[i] for directed sons 95 96 // let f'[i] = max{f[w] | w->i}+1, g'[i] = max{g[w] | i->w}+1 97 // then we should change some undirected edges to ->u or u-> edges so that f'[i]+g'[i] <= maxlen 98 // then f[i] is the minimal f'[i] under this condition, and g[i] is the minimal g'[i] 99 for(int k = 0; k < edges[i].size(); k++) { 100 int w = edges[i][k].v; 101 if(w == fa) continue; //ch != fa 102 dp(w, i); //Çó½âÍê×Ó½ÚµãºóÇó½âµ±Ç°½áµã 103 int d = edges[i][k].d; 104 if(d == 0) sons.push_back(UndirectedSon(w, f[w], g[w])); 105 else if(d == 1) g0 = max(g0, g[w]+1); 106 else f0 = max(f0, f[w]+1); 107 } 108 // If there is no undirected edges, we're done 109 if(sons.empty()) { 110 f[i] = f0; g[i] = g0; 111 if(f[i] + g[i] > maxlen) { f[i] = g[i] = INF; } 112 return f[i] < INF; 113 } 114 115 f[i] = g[i] = INF; 116 117 // to calculate f[i], we sort f[w] of undirected sons in increasing order and make first p edges to w->i 118 // then we calculate f'[i] and g'[i], check for f'[i]+g'[i] <= maxlen and update answer 119 int s = sons.size(); 120 sort(sons.begin(), sons.end(), cmp_f); 121 int maxg[maxn]; // maxg[i] is max{sons[i].g, sons[i+1].g, ...} 122 maxg[s-1] = sons[s-1].g; 123 for(int k = s-2; k >= 0; k--) 124 maxg[k] = max(sons[k].g, maxg[k+1]); 125 for(int p = 0; p <= sons.size(); p++) { 126 int ff = f0, gg = g0; 127 if(p > 0) ff = max(ff, sons[p-1].f+1); 128 if(p < sons.size()) gg = max(gg, maxg[p]+1); 129 if(ff + gg <= maxlen) f[i] = min(f[i], ff); 130 } 131 132 // g[i] is similar 133 sort(sons.begin(), sons.end(), cmp_g); 134 int maxf[maxn]; // maxf[i] is max{sons[i].f, sons[i+1].f, ...} 135 maxf[s-1] = sons[s-1].f; 136 for(int k = s-2; k >= 0; k--) 137 maxf[k] = max(sons[k].f, maxf[k+1]); 138 for(int p = 0; p <= sons.size(); p++) { 139 int ff = f0, gg = g0; 140 if(p > 0) gg = max(gg, sons[p-1].g+1); 141 if(p < sons.size()) ff = max(ff, maxf[p]+1); 142 if(ff + gg <= maxlen) g[i] = min(g[i], gg); 143 } 144 145 return f[i] < INF; 146 } 147 148 int main() { 149 while(read_data()) { 150 maxlen = 0; 151 for(int i = 1; i <= n; i++) maxlen = max(maxlen, dfs(i)); 152 // Note: the problem asks for the number of nodes in path, but all the "lengths" above mean "number of edges" 153 if(dp(root, -1)) cout << maxlen+1 << "\n"; 154 else cout << maxlen+2 << "\n"; 155 } 156 return 0; 157 }
posted on 2015-08-20 12:20 hahalidaxin 阅读(281) 评论(0) 编辑 收藏 举报