1. 题目描述
某树形网络由$n, n \in [1, 10^4]$台计算机组成。现从中选择一些计算机作为服务器,使得每当普通计算机恰好与一台服务器连接(并且不超过一台)。求需要指定服务器的最少数量
2. 基本思路
这显然是一个求最优解的问题,并且该网络拓扑结构为树形。因此,考虑树形DP。关键是考虑有哪些状态?不妨令
(1) $dp[u][0]$表示$u$作为服务器,那么它的儿子结点可以是服务器或者普通机;
(2) $dp[u][1]$表示$u$是普通计算机,但是$fa[u]$作为服务器,那么它的儿子结点一定是普通机;
(3) $dp[u][2]$表示$u$和$fa[u]$都是普通计算机,那么它的其中一个儿子结点是服务器。
因此,很容易推导状态转移。
\begin{align}
dp[u][0] &= 1 + \sum \min (dp[v][0], dp[v][1]) \\
dp[u][1] &= \sum dp[v][2] \\
dp[u][2] &= \min (dp[v][0] - dp[v][2]) + \sum dp[v][2] \notag \\
&= \min (dp[v][0] - dp[v][2]) + dp[u][1]
\end{align}
这里注意所求解是$\min (dp[rt][0], dp[rt][2])$,因为根节点没有父亲节点。这是树形DP中很经典的模型。
3. 代码
1 /* 3398 */ 2 #include <iostream> 3 #include <sstream> 4 #include <string> 5 #include <map> 6 #include <queue> 7 #include <set> 8 #include <stack> 9 #include <vector> 10 #include <deque> 11 #include <bitset> 12 #include <algorithm> 13 #include <cstdio> 14 #include <cmath> 15 #include <ctime> 16 #include <cstring> 17 #include <climits> 18 #include <cctype> 19 #include <cassert> 20 #include <functional> 21 #include <iterator> 22 #include <iomanip> 23 using namespace std; 24 //#pragma comment(linker,"/STACK:102400000,1024000") 25 26 #define sti set<int> 27 #define stpii set<pair<int, int> > 28 #define mpii map<int,int> 29 #define vi vector<int> 30 #define pii pair<int,int> 31 #define vpii vector<pair<int,int> > 32 #define rep(i, a, n) for (int i=a;i<n;++i) 33 #define per(i, a, n) for (int i=n-1;i>=a;--i) 34 #define clr clear 35 #define pb push_back 36 #define mp make_pair 37 #define fir first 38 #define sec second 39 #define all(x) (x).begin(),(x).end() 40 #define SZ(x) ((int)(x).size()) 41 #define lson l, mid, rt<<1 42 #define rson mid+1, r, rt<<1|1 43 #define INF 0x3f3f3f3f 44 #define mset(a, val) memset(a, (val), sizeof(a)) 45 46 typedef struct { 47 int v, nxt; 48 } edge_t; 49 50 51 const int maxv = 10005; 52 const int inf = 1e5; 53 const int maxe = maxv * 2; 54 int head[maxv], l; 55 edge_t E[maxe]; 56 int dp[maxv][3]; 57 int n; 58 59 void init() { 60 memset(head, -1, sizeof(head)); 61 l = 0; 62 } 63 64 inline void addEdge(int u, int v) { 65 E[l].v = v; 66 E[l].nxt = head[u]; 67 head[u] = l++; 68 69 E[l].v = u; 70 E[l].nxt = head[v]; 71 head[v] = l++; 72 } 73 74 void dfs(int u, int fa) { 75 int k; 76 77 dp[u][0] = 1; 78 dp[u][1] = 0; 79 dp[u][2] = inf; 80 for (k=head[u]; k!=-1; k=E[k].nxt) { 81 int& v = E[k].v; 82 if (v == fa) 83 continue; 84 dfs(v, u); 85 dp[u][0] += min(dp[v][0], dp[v][1]); 86 dp[u][1] += dp[v][2]; 87 dp[u][2] = min(dp[u][2], dp[v][0]-dp[v][2]); 88 } 89 90 91 dp[u][2] += dp[u][1]; 92 } 93 94 void solve() { 95 dfs(1, 0); 96 int ans = min(dp[1][0], dp[1][2]); 97 printf("%d\n", ans); 98 } 99 100 int main() { 101 ios::sync_with_stdio(false); 102 #ifndef ONLINE_JUDGE 103 freopen("data.in", "r", stdin); 104 freopen("data.out", "w", stdout); 105 #endif 106 107 int u, v; 108 109 while (scanf("%d",&n)!=EOF && n) { 110 init(); 111 rep(i, 1, n) { 112 scanf("%d%d",&u,&v); 113 addEdge(u, v); 114 } 115 solve(); 116 scanf("%d", &n); 117 if (n == -1) 118 break; 119 } 120 121 #ifndef ONLINE_JUDGE 122 printf("time = %ldms.\n", clock()); 123 #endif 124 125 return 0; 126 }
时间: 2024-10-11 11:45:47