POJ3659 Cell Phone Network【最小支配集】【贪心】
Farmer John has decided to give each of his cows a cell phone in hopes to encourage their social interaction. This, however, requires him to set up cell phone towers on his N (1 ≤ N ≤ 10,000) pastures (conveniently numbered 1..N) so they can all communicate.
Exactly N-1 pairs of pastures are adjacent, and for any two pastures A and B (1 ≤ A ≤ N; 1 ≤ B ≤ N; A ≠ B) there is a sequence of adjacent pastures such that A is the first pasture in the sequence and B is the last. Farmer John can only place cell phone towers in the pastures, and each tower has enough range to provide service to the pasture it is on and all pastures adjacent to the pasture with the cell tower.
Help him determine the minimum number of towers he must install to provide cell phone service to each pasture.
Input
* Line 1: A single integer: N
* Lines 2..N: Each line specifies a pair of adjacent pastures with two space-separated integers: A and B
Output
* Line 1: A single integer indicating the minimum number of towers to install
Sample Input
5
1 3
5 2
4 3
3 5
2
USACO 2008 January Gold
题目大意:John想让他的所有牛用上手机以便相互交流(也是醉了。。。),他需要建立
几座信号塔在N块草地中。已知与信号塔相邻的草地能收到信号。给你N-1个草地(A,B)
的相邻关系,问:最少需要建多少个信号塔能实现所有草地都有信号。
思路:考察树最小支配集问题。最小支配集:值从所有顶点中取尽量少的点组成一个集
合,使得剩下的所有点都与取出来的点有边相连。顶点个数最小的支配集被称为最小支
配集。这里用贪心法来求。
1.以1号点深度优先搜索整棵树,求出每个点在DFS中的编号和每个点的父亲节点编号。
2.按DFS的反向序列检查,如果当前点既不属于支配集也不与支配集中的点相连,且它
的父亲也不属于支配集,将其父亲点加入支配集,支配集个数加1。
3.标记当前结点、当前结点的父节点(属于支配集)、当前结点的父节点的父节点(与支配集
中的点相连)。
参考:ACM-ICPC程序设计系列——图论及应用 P66~P69
#include<iostream> #include<algorithm> #include<cstdio> #include<cstring> using namespace std; const int MAXN = 20020; struct EdgeNode { int to; int next; }Edges[MAXN]; int Head[MAXN],father[MAXN],NewPos[MAXN]; bool vis[MAXN]; //NewPos[]表示深度优先遍历序列的第i个点是哪个点 //now表示当前深度优先遍历序列中已经有多少个点了 //vis[]用来深度优先遍历的判重 //father[]表示点i的父亲节点编号 int N,M,now; void DFS(int x) { NewPos[now++] = x; for(int k = Head[x]; k != -1; k = Edges[k].next) { if(!vis[Edges[k].to]) { vis[Edges[k].to] = true; father[Edges[k].to] = x; DFS(Edges[k].to); } } } //S[i]为true,表示第i个点被覆盖了 //Set[i]表示点i属于要求的点集 bool S[MAXN],Set[MAXN]; int Greedy()//贪心求最小支配集 { memset(S,0,sizeof(S)); memset(Set,0,sizeof(Set)); int ans = 0; for(int i = N-1; i >= 1; i--)//反向序列检查 { int t = NewPos[i]; if(!S[t])//当前点未被覆盖,也就是当前点既不属于支配集,夜不语支配集中的点相连 { if(!Set[father[t]])//当前点的父亲结点不属于支配集, { Set[father[t]] = true; //将父节点加入支配集 ans++; //支配集个数加1 } S[t] = true; S[father[t]] = true; S[father[father[t]]] = true; //标记当前点、当前结点的父节点、当前结点的父节点的父节点 } } return ans; } int main() { int u,v; while(~scanf("%d",&N)) { memset(Edges,0,sizeof(Edges)); memset(Head,-1,sizeof(Head)); memset(father,0,sizeof(father)); memset(vis,false,sizeof(vis)); memset(NewPos,0,sizeof(NewPos)); int id = 0; for(int i = 0; i < N-1; ++i) { scanf("%d%d",&u,&v); Edges[id].to = v; Edges[id].next = Head[u]; Head[u] = id++; Edges[id].to = u; Edges[id].next = Head[v]; Head[v] = id++; } now = 0; vis[1] = true; father[1] = 1; DFS(1); printf("%d\n",Greedy()); } return 0; }
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。