POJ 3107 - Godfather
本题与POJ 1655的区别是要把所有重心的点按顺序输出出来。
// poj3107 Godfather #include <cstdio> #include <cstring> #define NDEBUG #define MAXN 50005 using namespace std; int N; int edgefw[MAXN*2], edge[MAXN*2], head[MAXN], eptr; #define EI(j, k) ({ \ edge[eptr] = k, edgefw[eptr] = head[j]; \ head[j] = eptr++; \ }) int dp[MAXN], dp2[MAXN]; char vis[MAXN]; void dfs(int i) { vis[i] = 1; int p, maxk = 0, sumn = 1; for(p = head[i]; p>=0; p = edgefw[p]) { int t = edge[p]; if (!vis[t]) { if (!dp2[t]) dfs(t); sumn += dp2[t]; if (maxk < dp2[t]) maxk = dp2[t]; } } if (sumn != N && N - sumn > maxk) maxk = N - sumn; dp[i] = maxk, dp2[i] = sumn; } int main(void) { #ifndef NDEBUG freopen("poj3107.in", "r", stdin); #endif // NDEBUG scanf("%d", &N); memset(head, -1, sizeof(int) * N), eptr = 0; int i, j, root; root = 0; for(i=1; i<N; ++i) { int k; scanf("%d%d", &j, &k); --j,--k; EI(j, k), EI(k, j); if (root == k) root = j; } dfs(root); j = 0; for(i = 1; i < N; ++i) if (dp[i] < dp[j]) j = i; root = 0; for(i = 0; i < N; ++i) if (dp[i] == dp[j]) { printf("%d", ++i); break; } for(; i<N; ++i) if (dp[i] == dp[j]) printf(" %d", i+1); putchar('\n'); return 0; }
3107 | Accepted | 4104K | 532MS | G++ | 1249B | 2014-05-01 01:22:57 |
5/3更新 求树的重心模板:
1 #include <cstdio> 2 #include <cstring> 3 using namespace std; 4 5 6 #define FOR(p,i,s,t) for(__typeof(p) i=s; i<t; ++i) 7 #define REP(t,i,n) FOR(t,i,0,n) 8 9 #define ECH(it, A) for (__typeof(A.begin()) it=A.begin(); it != A.end(); ++it) 10 #define RST(x,y) memset(x, y, sizeof(x)) 11 #define RST0(x) RST(x,0) 12 13 typedef int Vt, Lt; 14 const __typeof(Vt) MAXV = 50005; 15 16 #define MAXE ((MAXV<<1) - 2) 17 18 Vt Vefw[MAXE], Veh[MAXV], eptr = 0; 19 struct Vedge { 20 Vt t; 21 Lt l; 22 Vedge() {} 23 Vedge(Vt _t): t(_t), l(1) {} 24 Vedge(Vt _t, Lt _l): t(_t), l(_l) {} 25 void attach(Vt s) { 26 extern Vedge Vs[]; 27 memcpy(Vs + eptr, this, sizeof(Vedge)); 28 Vefw[eptr] = Veh[s]; Veh[s] = ++eptr; 29 } 30 }; 31 #define addedge(s,t,l) ({Vedge e(t,l); e.attach(s);}) 32 Vedge Vs[MAXE]; 33 Vt gcoref_tot; 34 char gc_8[MAXV]; 35 Vt gc_maxk[MAXV], gc_sumn[MAXV]; 36 37 int gc_root; 38 39 void gcoref(Vt i) 40 { 41 char _gc8; 42 if (!(_gc8 = gc_8[i])) gc_8[i] = -1; // 遍历去环 43 Vt sumn = 1, maxk = 0; 44 for(Vt e = Veh[i]; e; e = Vefw[e]) { 45 Vt t = Vs[--e].t; 46 if (!gc_8[t]) { 47 gcoref(t); 48 sumn += gc_sumn[t]; 49 if (maxk < gc_sumn[t]) 50 maxk = gc_sumn[t]; 51 } 52 } 53 gc_8[i] = _gc8; // gc_8还有其他用途 54 if (gcoref_tot - sumn > maxk) maxk = gcoref_tot - sumn; 55 gc_sumn[i] = sumn, gc_maxk[i] = maxk; 56 if (gc_maxk[gc_root] > maxk) gc_root = i; 57 } 58 59 inline Vt gcore(Vt root) 60 { 61 gc_maxk[gc_root = root] = gcoref_tot; 62 gcoref(root); 63 return gc_root; 64 } 65 66 int N; 67 68 // 本模板使用方式: gcoref_tot = 实际节点数 69 // gc_8 != 0, 该节点被剪掉(忽略),可以用来存储其他信息 70 // addedge加边(注意针对 无根树 要加双向),gcore返回重心节点 71 // gc_maxk里面存储所有节点的最大真子树的节点数. 72 73 int main(void) 74 { 75 // freopen("poj3107.txt", "r", stdin); 76 scanf("%d", &N); 77 Vt root = 0; 78 REP(int, i, N-1) { 79 Lt l; 80 Vt s,t; 81 scanf("%d%d", &s, &t); --s, --t; 82 addedge(s,t,1), addedge(t,s,1); 83 if (root == t) root = s; 84 } 85 gcoref_tot = N; 86 root = gcore(root); 87 Vt i; 88 for(i = 0; i < N; ++i) 89 if (gc_maxk[i] == gc_maxk[root]) { 90 printf("%d", ++i); 91 break; 92 } 93 for(; i<N; ++i) 94 if (gc_maxk[i] == gc_maxk[root]) 95 printf(" %d", i+1); 96 putchar('\n'); 97 return 0; 98 }
This article is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
本文采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。