1. 程式人生 > >hdu-6228 Tree 2017年ICPC瀋陽站L題 DFS+思維

hdu-6228 Tree 2017年ICPC瀋陽站L題 DFS+思維

題目連結

題意

        題目比較難理解,讀懂樣例就會好一點。大概就是給出一棵有N個結點的樹,有K種色彩對樹的結點進行染色,然後連線所有相同顏色的點,並將經過的邊組成一個邊集Ei,最後取所有邊集的交集的最大值。說白了就是連線所有顏色相同的點,看有幾個邊所有顏色的路線都經過。求這個的最大值。

題解

        這個題最開始想的是,每個點可以是多個邊的結點,因為我們需要考慮某個邊是否能讓所有的集合都經過,換而言之,只有這個點有多個邊經過,那麼這個點對應的邊就是交集邊。所以計算每個結點經過邊的數量,大於1的全部整合起來再減1就是答案。當然這只是最簡單的思想,絕對是錯的。不過整體思路是沒問題的:即找到那些邊可以被經過多次。

        為了使一個邊能被所有的顏色經過,最簡單思路:這個結點的所有子結點的數量>=K,這樣如果子結點最大可能是所有種類的顏色都從這個結點經過,那麼這個邊就是解集邊。

        第一次這樣寫的時候WA了,後來才想到這樣我們可能將根或者比較高層的結點也算進去,因為是無向圖,所以我們應該考慮以一個結點為中心,分隔整個圖,要求左邊的結點和右邊的結點同時>=K,那麼這個結點最大可能下能經過至少K次,就是解集邊。

        那麼就比較容易解決了,首先DFS統計所有結點的子結點數量。因為一定是樹,那麼隨便找個結點當做根就可以,統計的子結點數M就是一側的結點數量,另一側就是N-M。最後遍歷整個結點,滿足M >=K

 && N-M>=K的結點就是解集邊的一個點。

        資料的儲存方面,我是利用vector陣列,即利用鄰接表的方式儲存,滿足題目給出的要求。

C++ AC 程式碼 140ms

#include<iostream>
#include<vector>
#include<list>
#include<string>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<utility>
#include<queue>
#include<sstream>
#include<iterator>
#include<math.h>
#include<malloc.h>
#include<string.h>
#include<stack>
#include<functional>
#define TIME std::ios::sync_with_stdio(false)
#define LL long long
#define MOD 1000000007
#define MAX 201000
#define INF 0x3f3f3f3f

using namespace std;

int T,N,K;
int number[MAX],step[MAX];
vector<int> maps[MAX];

int dfs(int root){
    int len = maps[root].size();
    if(len == 0) return 1;
    for(int i = 0;i < len;i++){
        if(step[i] == 1) continue;
        step[i] = 1;
        number[root] += dfs(maps[root][i]);
    }
    return number[root];
}

int main() {
    TIME;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&N,&K);
        memset(step,0,sizeof(step));
        for(int i = 0;i <= N;i++){
            maps[i].clear();
            number[i] = 1;
        }
        int a,b;
        for(int i = 0;i < N-1;i++){
            scanf("%d%d",&a,&b);
            maps[a].push_back(b);
            maps[b].push_back(a);
        }
        step[1] = 1;
        dfs(1);
        int ans = 0;
        for(int i = 1;i <= N;i++){
            if(number[i] >= K && number[i] <= (N - K)){
                ans++;
            }
        }
        printf("%d\n",ans);
    }

    system("pause");
    return 0;
}