1. 程式人生 > >P3942 將軍令

P3942 將軍令

P3942 將軍令

夢裡,小 F 成了一個給將軍送密信的信使。

現在,有兩封關乎國家生死的密信需要送到前線大將軍帳下,路途凶險,時間緊迫。小 F 不因為自己的禍福而避趨之,勇敢地承擔了這個任務。

不過,小 F 實在是太粗心了,他一不小心把兩封密信中的一封給弄掉了。

小 F 偷偷打開了剩下的那封密信。他 發現一副十分詳細的地圖,以及幾句批文——原來 這是戰場周圍的情報地圖。他仔細看後發現,在這張地圖上標記了 n 個從 1 到 n 標號的 驛站,n − 1 條長度為 1 裡的小道,每條小道雙向連線兩個不同的驛站,並且驛站之間可以 通過小道兩兩可達。

小 F 仔細辨認著上面的批註,突然明白了丟失的信的內容了。原來,每個驛站都可以駐 扎一個小隊,每個小隊可以控制距離不超過 k 裡的驛站。如果有驛站沒被控制,就容易產 生危險——因此這種情況應該完全避免。而那封丟失的密信裡,就裝著朝廷數學重臣留下的 精妙的排布方案,也就是用了最少的小隊來控制所有驛站。

小 F 知道,如果能計算出最優方案的話,也許他就能夠將功贖過,免於死罪。他找到了 你,你能幫幫他嗎? 當然,小 F 在等待你的支援的過程中,也許已經從圖上觀察出了一些可能會比較有用的 性質,他會通過一種特殊的方式告訴你。

Solution

很早做的題, 那時沒部落格
今天做了類似的, 貌似資料有點問題。。
好的這題可以貪心
我們從深度大的節點開始, 可以發現在深度與這個節點差 \(\leq k\) 的節點駐紮, 此點可以被控制
那麼當然染最遠那個點優, 可以夠得到上面一點的點
於是從深度大的開始, 若沒被染色則上訪到最遠處, 染色, 順便將能染得都染了
順便累計答案即可

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
typedef long long LL;
using namespace std;
int RD(){
    int out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const int maxn = 1000019,INF = 1e9;
int head[maxn],nume = 1;
struct Node{
    int v,dis,nxt;
    }E[maxn << 3];
void add(int u,int v,int dis){
    E[++nume].nxt = head[u];
    E[nume].v = v;
    E[nume].dis = dis;
    head[u] = nume;
    }
int num,k;
int fa[maxn];
struct T{
    int index,dep;
    }I[maxn];
bool cmp(T a,T b){return a.dep > b.dep;}
bool vis[maxn];
int dep[maxn];
void dfs1(int u,int F){
    for(int i = head[u];i;i = E[i].nxt){
        int v = E[i].v;
        if(v == F)continue;
        I[v].dep = dep[v] = I[u].dep + 1;
        dfs1(v,u);
        }
    }
bool used[maxn];
void dfs2(int u,int left){
    vis[u] = 1;
    used[u] = 1;
    for(int i = head[u];i;i = E[i].nxt){
        int v = E[i].v;
        if(!used[v] && left > 0)dfs2(v,left - 1);
        }
    used[u] = 0;
    }
int col;
void find(int u,int left){
    col = u;
    if(left == 0)return ;
    for(int i = head[u];i;i = E[i].nxt){
        int v = E[i].v;
        if(dep[v] > dep[u])continue;
        find(v,left - 1);
        }
    }
int ans;
void check(){
    for(int i = 1;i <= num;i++){
        if(!vis[I[i].index]){
            ans++;
            find(I[i].index,k);
            dfs2(col,k);
            }
        }
    printf("%d\n",ans);
    }
int main(){
    num = RD();k = RD();RD();
    for(int i = 1;i <= num - 1;i++){
        int u = RD(),v = RD();
        add(u,v,1);add(v,u,1);
        I[i].index = i;//這裡和輸入路徑無關
        }
    I[num].index = num;
    I[1].dep = dep[1] = 1;
    dfs1(1,-1);
    sort(I + 1,I + 1 + num,cmp);
    check();
    return 0;
    }