【POJ】3398 Perfect Service

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 }

 

posted on 2016-03-30 12:03  Bombe  阅读(252)  评论(0编辑  收藏  举报

导航