1. 程式人生 > >Aiiage Camp Day1 C Littrain wanna be different

Aiiage Camp Day1 C Littrain wanna be different

spa line diff size wan pre ini style min

題意

  給一棵N個點的樹,每個點有一個顏色。問含有至少k種顏色的最小連通塊的大小。

  1<=n<=1e4, 1<=k<=5,1<=顏色數<=n

題解

  如果只有k種顏色,有個顯然的O(3^k*n)的DP。

  DP[i][j]表示以i為根的樹,顏色狀態為j的最小連通塊大小。j用k位二進制數表示。DFS轉移,每次枚舉所有狀態即可。

  那麽將所有顏色映射到[1,k],做這樣的DP,正確概率為k!/k^k。多隨機幾次即可。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 int
n, k, tot(0), e[20010], G[10010], nxt[20010], c[10010], col[10010], dp[10010][50]; 5 6 void addedge(int u, int v) 7 { 8 e[++tot] = u; nxt[tot] = G[v]; G[v] = tot; 9 e[++tot] = v; nxt[tot] = G[u]; G[u]=tot; 10 } 11 12 inline void init() 13 { 14 srand(0); 15 scanf("%d%d", &n, &k); 16 for
(int i = 1; i <= n; ++i) 17 scanf("%d", c + i); 18 for (int i = 1; i < n; ++i) 19 { 20 int x, y; 21 scanf("%d%d", &x, &y); 22 addedge(x, y); 23 } 24 } 25 26 inline void DFS(int now, int fa) 27 { 28 dp[now][col[c[now]]] = 1; 29 for (int
i = G[now]; i; i = nxt[i]) 30 if (e[i] != fa) 31 { 32 DFS(e[i], now); 33 for (int j = 0; j < (1 << k); ++j) 34 for (int k = j; k; k = (k - 1) & j) 35 dp[now][j] = min(dp[now][j], dp[now][k ^ j] + dp[e[i]][k]); 36 } 37 for (int j = 0; j < (1 << k); ++j) 38 for (int k = j; k; k = (k - 1) & j) 39 dp[now][k] = min(dp[now][k], dp[now][j]); 40 dp[now][0] = 0; 41 } 42 43 inline int Work() 44 { 45 memset(dp, 1, sizeof dp); 46 DFS(1, 0); 47 return dp[1][(1 << k) - 1]; 48 } 49 50 inline void solve() 51 { 52 int ans(1000000000); 53 for (int ii = 0; ii < 50; ++ii) 54 { 55 for (int i = 1; i <= n; ++i) 56 col[i] = 1 << rand() % k; 57 ans = min(ans, Work()); 58 } 59 printf("%d\n", ans); 60 } 61 62 int main() 63 { 64 init(); 65 solve(); 66 67 return 0; 68 }

Aiiage Camp Day1 C Littrain wanna be different