UVa #1380 A Scheduling Problem (例题9-26)
来源:互联网 发布:手机购彩大乐透软件 编辑:程序博客网 时间:2024/06/11 11:55
居然一次就过了。。做了两天,泪流满面啊。不过代码跑得很慢。。有机会优化一下
这道题想清楚了还是很简单的,但是一开始的思路不容易理顺。下面文中我的f和g与Rujia书中的定义相反,请注意区分。
题目里说,把所有的无向边去掉之后,最终答案则一定是由剩下的有向边组成的最长路径长度k或者k+1。
所以我们的工作就变成了:给无向边分配方向,使得最后得到的树里,最长路径长度不大于k。若可以做到则答案为k,否则答案为k+1
对于树中某一个以结点a为根的子树来说(即不考虑a的祖先),经过a的最长有向路经s等于下行最长路+上行最长路。我们设这两条路的长度分别为f和g,则经过a的最长路经s的结点数为f+g+1。
转化无向边的过程分为两种情况:
a. 如果一个子树中不存在无向边,则经过子树的根结点的最长有向路结点数为f+g+1(recall that f是下行的最长路长度,g是上行的最长路长度)。
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满足了要求就可以得出结果并终止枚举。复杂度为线性。
求g的过程相同,按照g值排序、枚举即可。
需要注意的细节包括
1、容易混淆边的长度和边上结点的数量
2、f、g值在计算的时候什么时候要+1,什么时候不应该+1,要仔细考虑
3、dir数组的大小问题
4、枚举的边界值 - 全部换成下行/上行的情况
Run Time: 0.022s
#define UVa "LT9-26.1380.cpp"//A Scheduling Problemchar fileIn[30] = UVa, fileOut[30] = UVa;#include<cstring>#include<cstdio>#include<algorithm>#include<vector>#include<iostream>using namespace std;//Global Variables. Reset upon Each Case!typedef pair<int,int> Pair;const int maxn = 200 + 5, DOWN = 0, UP = 1, UND = 2, INF = 1<<30;int dir[150];vector<int> G[maxn];vector<int> Gdir[maxn];int f[maxn], g[maxn];int n, x, k;int vis[maxn], len[maxn][2], lenvis[maxn][2];/////int dfs(int u, int direction);void readSon(int fa);void readG(int u);void clearG();void dp(int u, int& ans_f, int& ans_g) { if(vis[u]) { ans_f = f[u]; ans_g = g[u]; return; } vis[u] = 1; f[u] = g[u] = INF; if(G[u].size() == 0) { //leaf node ans_f = ans_g = f[u] = g[u] = 0; return; } int f_prime = 0, g_prime = 0, f_w, g_w; vector<Pair> und_f, und_g; for(int i = 0; i < G[u].size(); i ++) { dp(G[u][i], f_w, g_w); if(Gdir[u][i] == UND) { und_f.push_back(Pair(f_w, g_w)); und_g.push_back(Pair(g_w, f_w)); } else if(Gdir[u][i] == DOWN) f_prime = max(f_prime, f_w+1); else if(Gdir[u][i] == UP) g_prime = max(g_prime, g_w+1); } //f_prime and g_prime is len of longest directed path of sons. //und_f and und_g is the array of undirected path. if(und_f.size() == 0) { if(f_prime + g_prime +1 <= k) //all the '+1' in this kind of inequation is for current node. ans_f = f[u] = f_prime, ans_g = g[u] = g_prime; else ans_f = ans_g = f[u] = g[u] = INF; return; } sort(und_f.begin(), und_f.end()); sort(und_g.begin(), und_g.end()); int max_und_f[maxn], max_und_g[maxn]; max_und_f[und_g.size()-1] = und_g[und_g.size() - 1].second; max_und_g[und_f.size()-1] = und_f[und_f.size() - 1].second; for(int i = und_f.size() - 2; i >= 0; i --) { max_und_f[i] = max(max_und_f[i+1], und_g[i].second); max_und_g[i] = max(max_und_g[i+1], und_f[i].second); } max_und_g[und_f.size()] = max_und_f[und_g.size()] = -1; //max_und_g/f is the longest path up/down in element i - n. if(f_prime + max(max_und_g[0]+1, g_prime) + 1 <= k) { //turn all und into up f[u] = f_prime; } else for(int p = 0; p < und_f.size(); p ++) { if(max(und_f[p].first+1, f_prime) + max(max_und_g[p+1]+1, g_prime) + 1 <= k) { f[u] = max(und_f[p].first+1, f_prime); break; } } if(max(max_und_f[0]+1, f_prime) + g_prime +1 <= k) { //turn all und into down g[u] = g_prime; } else for(int p = 0; p < und_g.size(); p ++) { if(max(max_und_f[p+1]+1, f_prime) + max(und_g[p].first+1, g_prime) + 1 <= k) { g[u] = max(und_g[p].first+1, g_prime); break; } } ans_f = f[u]; ans_g = g[u];}int main() { int u; dir['d'] = DOWN, dir['u'] = UP, dir[' '] = UND; clearG(); while(scanf("%d", &u) && u) { readG(u); //k is the # of vertices of the longest monotonically directed path in the tree. //the answer shuold be k or k+1. memset(lenvis, 0, sizeof(lenvis)); memset(len, 0, sizeof(len)); k = 0; for(int i = 1; i <= n; i ++) { k = max(k, dfs(i, UP)+dfs(i, DOWN)+1); } memset(f, -1, sizeof(f)); memset(g, -1, sizeof(g)); memset(vis, 0, sizeof(vis)); int f_root, g_root; dp(1, f_root, g_root); if(f_root == INF || g_root == INF) k++; printf("%d\n", k); clearG(); } return 0;}int dfs(int u, int direction) { //calculate the value of k if(lenvis[u][direction]) return len[u][direction]; lenvis[u][direction] = 1; len[u][direction] = 0; for(int i = 0; i < G[u].size(); i ++) { if(Gdir[u][i] == direction){ len[u][direction] = max(len[u][direction], dfs(G[u][i], direction) + 1); } } return len[u][direction];}void readSon(int fa) { int son; char c; while( scanf("%d%c", &son, &c) && son ) { G[fa].push_back(son); Gdir[fa].push_back(dir[c]); }}void readG(int u) { readSon(u); n = 1; while(scanf("%d", &u) && u && n++) readSon(u);}void clearG() { for(int i = 1; i < maxn; i ++) { G[i].clear(); Gdir[i].clear(); }}
- UVa #1380 A Scheduling Problem (例题9-26)
- A Scheduling Problem UVA
- 1380 - A Scheduling Problem
- 【暑假】[深入动态规划]UVa 1380 A Scheduling Problem
- uva 1380 - A Scheduling Problem 一个调度问题 好难的动态规划
- poj3396 A Scheduling Problem
- UVALive-3683 A Scheduling Problem(treedp)
- UVA 101 The blocks problem 例题整理
- UVa #1025 A Spy in the Metro (例题9-1)
- A Dicey Problem UVA
- A Dicey Problem UVA
- A Research Problem UVA
- A Research Problem UVA
- UVALive 3683 A Scheduling Problem(树形DP)
- Task Scheduling problem.
- uva 387 - A Puzzling Problem
- UVA 11069 - A Graph Problem
- UVA 11069 A Graph Problem
- 8902382_52671.jpg
- p_large_BdpS_4af60000080d5c3f.jpg
- C language tutorial Chapter fifth: function
- 1.png
- 11.png
- UVa #1380 A Scheduling Problem (例题9-26)
- 000.jpg
- p_large_BdpS_4af60000080d5c3f1.jpg
- CAGradientLayer简介
- 建议 3.10:存储过程、函数中的输入、输出参数及变量的命名应该有所区分,包中的全局变量和局部变量命名也应有所区分。
- cropped-admin-ajax.jpg
- 0001.jpg
- How to solve: when using tab in gnomeTerminal , the entire screen flash,
- The method using the Chinese input method in Fedora 16