source: http://acm.hdu.edu.cn/showproblem.php?pid=3894
title : East and West
这道题贪心就可以解决了,首先找到一条把东西部的点分割开的边
(est, wst),然后从wst开始bfs,直到找到西部的p个点,并把这p个点
到wst的距离放到minp数组里。对于东部里最初有train的点也做类似的操作,但把
这p个距离放在t数组里。
这时的minp和t数组的数值都是不降的(BFS的性质所决定)。由于这p个train都要经由边(est, wst)到达
西部的点,所以t数组里的数字不能是相同的!比如4,4,4,5,最终被调整为4,5,6,7,
也就是说对于数组t的第i个元素t[i],得和它前面的时间的最大值(表示为maxt)+1进行比较。
最后把t里的数字和minp里的数字相加(不是对应相加, 而是第i个和第(p-i-1)个相加,也就是
较小的和较大的相加),最后算出来的ans还得加上经过边(est, wst)的时间(即1)。
#include <iostream> #include <stdio.h> using namespace std; const int N = 1000005; struct e{ int v; e* nxt; }es[N<<1], *fir[N], stk[N]; int n, m, en, p; int E, W; bool hasFood[N]; int eastNum[N], westNum[N], par[N]; int minp[N], t[N], que[N], dep[N]; inline void add_e(int u, int v){ es[en].v = v; es[en].nxt = fir[u]; fir[u] = &es[en++]; } template <typename T> void getNum(T& a){ a = 0; char ch; while(true){ ch = getchar(); if(ch >= '0' && ch <= '9') break; } a = ch - '0'; while(true){ ch = getchar(); if(ch < '0' || ch > '9') break; a = a * 10 + ch - '0'; } } bool input(){ if(scanf("%d%d%d%d", &n, &m, &E, &W)== EOF) return false; int i, u, v; en = 0; for(i = 1; i <= n; i++){ fir[i] = NULL; hasFood[i] = false; } for(i = 1; i < n; i++){ getNum<int>(u); getNum<int>(v); add_e(u, v); add_e(v, u); } scanf("%d", &p); for(i = 1; i <= p; i++){ getNum(u); hasFood[i] = true; } return true; } inline bool isEast(int u){ return u <= E; } inline bool has(int u) { return hasFood[u]; } inline bool isWest(int u){ return u >= n - W + 1; } inline void push(int v, int p, int& top){ eastNum[v] = westNum[v] = 0; if(isEast(v)){ eastNum[v]++; }else if(isWest(v)){ westNum[v]++; } ++top; stk[top].v = v; stk[top].nxt = fir[v]; par[v] = p; } typedef bool (*fun)(int u); void bfs(int st, int* ar, fun check){ int l, r, u, v, num; e* cur; l = r = num = 0; que[r++] = st; dep[st] = 0; if(check(st)){ ar[num++] = 0; } while(l != r && num < p){ u = que[l++]; for(cur = fir[u]; cur; cur = cur->nxt){ if((v = cur->v) != par[u]){ que[r++] = v; par[v] = u; dep[v] = dep[u] + 1; if(check(v)){ ar[num++] = dep[v]; if(num >= p) break; } } } } } void solve(){ int top = -1, u, v, est, wst, ans; int i, maxt; push(1, -1, top); while(top >= 0){ u = stk[top].v; if(stk[top].nxt == NULL){ if(eastNum[u] == 0 && westNum[u] == W){ wst = u; est = par[u]; break; } if(eastNum[u] == E && westNum[u] == 0){ wst = par[u]; est = u; break; } if(par[u] >= 1){ eastNum[par[u]] += eastNum[u]; westNum[par[u]] += westNum[u]; } top--; continue; }else{ v = stk[top].nxt->v; stk[top].nxt = stk[top].nxt->nxt; if(v != par[u]){ push(v, u, top); } } } par[est] = wst; par[wst] = est; bfs(wst, minp, isWest); bfs(est, t, has); ans = 0; maxt = -1; for(i = 0; i < p; i++){ if(t[i] < maxt + 1) t[i] = maxt + 1; maxt = t[i]; if(ans < t[i] + minp[p - i - 1]){ ans = t[i] + minp[p - i - 1]; } } ans++; cout<<ans<<endl; } int main() { while(input()) solve(); return 0; }