题意:给一个树状图,有n个点。求出,去掉哪个点,使得剩下的每个连通子图中点的数量不超过n/2。如果有很多这样的点,就按升序输出。n<=10000
思路:输入图后,先DFS建立树。对于节点x,记a[x]为包含自己在内x的子树中的结点个数。所以,如果一个点可以被去掉,那么n-a[x],以及所有a[j](j是x的子树的根节点)都不大于n/2。另一个问题在于n<=10000,所以不能建立邻接矩阵, 而是用vector。在我的程序中,在dfs时已经标记了每个点是否能作为结果res。最后顺序输出就行了。
统计:1Y, 47ms
#include <iostream> #include <vector> #define F(i,a,b) for (int i=a;i<=b;i++) #define MS(x) memset(x, 0, sizeof(x) ) #define PB push_back using namespace std; const int maxn = 10002; bool mk[maxn], res[maxn]; int a[maxn], half, n; vector<int> v[maxn]; int dfs(int x) { int len = v[x].size(); a[x] = 1; mk[x] = true; bool ok = true; F(i,0,len-1) { int j = v[x][i]; if (!mk[j]) { int temp = dfs(j); if (temp>half) ok = false; a[x]+=temp; } } if (ok && n-a[x] <=half) res[x] = true; return a[x]; } int main() { scanf("%d", &n); F(i,1,n-1) { int a,b; scanf("%d%d", &a, &b); v[a].PB(b); v[b].PB(a); } half = n/2; mk[1] = true; dfs(1); F(i,1,n) if (res[i]) cout << i << endl; return 0; }