題目連結
給你一棵樹,讓你切斷一些邊,使得剩下的每個連通塊的點的個數的乘積最大,輸出這個乘積。
n <= 700
首先,答案肯定要用高精度儲存。。。。
可以貪心,也可以背包。
隨便畫一畫可以發現剩下的連通塊中,不會有某塊包含長度>=3的路徑,因為可以找到中間的那條邊切斷,使得這個路徑分成兩段a 和 b (a>=2 ,b >=2), a*b>=a+b
根據這個推論 , 可以分三種情況
1:以u為根 ,且u與所有的兒子隔開
2::u與一些兒子相連,兒子們與孫子們都是斷開的,不然就會有>=3的路徑出現
3:u與某個兒子相連,然後這個兒子與一些孫子相連,再往下都是斷開的
假設h[i]為以i為子樹的答案 f[i]為 Πhj ,j是i的兒子
那麼對於第一種情況,答案為f[u],第二種情況的話u需要串連上一些子樹,串連某個兒子v的代價是f[u] / h[v] * f[v],所以如果只串連一個兒子,肯定就選f[v]/h[v]最大的那個兒子,因此可以先將所有的f[v]/h[v]排序,枚舉一遍就好了。
第三種情況與第二種類似。。。。
如果用背包做的話狀態大概是這樣的dp[i][j] 表示以i為根的子樹串連了j-1個兒子的最大乘積,(即i所在連通塊有j個點)。轉移的時候是最普通的那種轉移,不過這種做法顯然沒有注意到上面的推論。。。
import java.util.*;import java.math.*;import java.io.*;public class Main { public static void main(String[] args) { InputStream inputStream = System.in; OutputStream outputStream = System.out; InputReader in = new InputReader(inputStream); PrintWriter out = new PrintWriter(outputStream); AC solver = new AC(); solver.solve(in, out); out.close(); }}class AC { class Node { BigInteger h, f; } Comparator<Integer> cmp = new Comparator<Integer>() { public int compare(Integer a,Integer b) { return dp[b].f.multiply(dp[a].h).compareTo(dp[a].f.multiply(dp[b].h)); } }; ArrayList<Integer> edge[] = new ArrayList[710]; Node dp[] = new Node[710]; int size[] = new int[710]; void dfs(int u, int f,PrintWriter out) { dp[u].f = dp[u].h = BigInteger.ONE; size[u] = 1; // case 1 : u's component is only u for(int v:edge[u]) { if(v == f) continue; dfs(v,u,out); dp[u].f = dp[u].f.multiply(dp[v].h); size[u] += size[v]; } Collections.sort(edge[u],cmp); // case 2 : u is with some of its children dp[u].h = dp[u].f; BigInteger cur; cur = dp[u].f; int son = 0; for(int v:edge[u]){ if(v==f) continue; son ++; cur = cur.divide(dp[v].h).multiply(dp[v].f); BigInteger tmp = cur.multiply(BigInteger.valueOf(son+1)); if(tmp.compareTo(dp[u].h) > 0) dp[u].h = tmp; } // case 3: u is with only one of its children and some children's children for(int v :edge[u]) { if(v==f) continue; cur = dp[u].f.divide(dp[v].h).multiply(dp[v].f); son = 0; for(int w : edge[v]) { if(w == u) continue; son++; cur = cur.divide(dp[w].h).multiply(dp[w].f); BigInteger tmp = cur.multiply(BigInteger.valueOf(son+2)); if(tmp.compareTo(dp[u].h) > 0) dp[u].h = tmp; } } } public void solve(InputReader in, PrintWriter out) { int n, a, b; n = in.nextInt(); for (int i = 1; i <= n; i++){ edge[i] = new ArrayList<Integer>(); dp[i] = new Node(); } for (int i = 1; i < n; i++) { a = in.nextInt(); b = in.nextInt(); edge[a].add(b); edge[b].add(a); } dfs(1,0,out); out.println(dp[1].h); }}class InputReader { BufferedReader reader; StringTokenizer tokenizer; public InputReader(InputStream stream) { reader = new BufferedReader(new InputStreamReader(stream)); tokenizer = null; } public String next() { while (tokenizer == null || !tokenizer.hasMoreTokens()) { try { tokenizer = new StringTokenizer(reader.readLine()); } catch (IOException e) { throw new RuntimeException(e); } } return tokenizer.nextToken(); } public int nextInt() { return Integer.parseInt(next()); } public double nextDouble() { return Double.parseDouble(next()); } public long nextLong() { return Long.parseLong(next()); }}