sgu280:Trade centers(貪心構造)

題目大意:
       給定一棵n 個結點的樹,從中選出一個最小點集S ,使得樹中每一個點到點集的最小距離k

分析:
       根據貪心原則,每兩個S 中的點,儘量使得兩個點之間的距離=2k+1 ,因爲如果兩個點距離2k+1 ,中間所有的點都是可以覆蓋得到的。
      fi 表示i 到子樹中某一個S 中的點的距離。
       如果i 爲葉子結點,fi=k+1 ,表示它只能由kth ancestor 覆蓋( 看不懂請往下)
       如果i 有一個孩子j ,那麼fi=fj+1
       如果i 有兩個以上的孩子,那麼從孩子中選一個最大的fmax ,和最小的fmin 。如果fmin+fmax2k+1 ,表示這棵子樹中所有的點都可以被覆蓋,fi=fmin+1 ,沒必要再選根結點;如果fmin+fmax>2k+1 ,表示這棵子樹中所有的點沒有都被覆蓋,那麼這時fi=fmax+1 。如果fi=2k+1 ,那麼將這個點加入S 中,fi 置爲0
       對於根節點,如果f1>k 那麼也要將其加入S 中。

AC code:

#include <cstdio>
#include <vector>
#include <algorithm>
#define pb push_back
using namespace std;

const int MAXN = 30009;
const int INF = 0x3f3f3f3f;

int n, k;
int rank[MAXN];
bool is[MAXN];
vector<int> ans;

struct Ugraph
{
    int size;
    int head[MAXN];
    int to[MAXN<<1];
    int ne[MAXN<<1];
    Ugraph() {size = 1;}
    void add_edge(int u, int v)
    {
        to[size] = v, ne[size] = head[u], head[u] = size++;
        to[size] = u, ne[size] = head[v], head[v] = size++;
    }
}G;

void dfs(int x, int fa)
{
    int y, minr = INF, maxr = -INF, c = 0;
    for(int i = G.head[x]; i; i = G.ne[i])
    {
        y = G.to[i];
        if(y != fa)
        {
            dfs(y, x);
            minr = min(minr, rank[y]);
            maxr = max(maxr, rank[y]);
            c++;
        }
    }
    if(!c) rank[x] = k+1;
    else if(c == 1) rank[x] = minr+1;
    else 
    {
        if(minr+maxr+2 <= 2*k+1) rank[x] = minr+1;
        else rank[x] = maxr+1;
    }
    if(rank[x] == 2*k+1) is[x] = true, rank[x] = 0;
}

int main()
{
    #ifndef ONLINE_JUDGE
    freopen("input.txt", "r", stdin);
    freopen("output.txt", "w", stdout);
    #endif

    scanf("%d%d", &n, &k);
    for(int i = 1; i < n; ++i)
    {
        int u, v;
        scanf("%d%d", &u, &v);
        G.add_edge(u, v);
    }
    dfs(1, 0);
    for(int i = 1; i <= n; ++i)
        if(is[i] || (i == 1 && rank[i] > k))
            ans.pb(i);
    printf("%d\n", ans.size());
    for(int i = 0, sz = ans.size(); i < sz; ++i)
        printf("%d\n", ans[i]);

    #ifndef ONLINE_JUDGE
    fclose(stdin);
    fclose(stdout);
    #endif
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章