您的位置:首页 > 理论基础 > 计算机网络

BZOJ 1596: [Usaco2008 Jan]电话网络 树形dp||贪心

2017-10-18 20:02 483 查看

1596: [Usaco2008 Jan]电话网络

Time Limit: 10 Sec Memory Limit: 162 MB

Submit: 1100 Solved: 513

[Submit][Status][Discuss]

Description

Farmer John决定为他的所有奶牛都配备手机,以此鼓励她们互相交流。不过,为此FJ必须在奶牛们居住的N(1 <= N <= 10,000)块草地中选一些建上无线电通讯塔,来保证任意两块草地间都存在手机信号。所有的N块草地按1..N 顺次编号。 所有草地中只有N-1对是相邻的,不过对任意两块草地A和B(1 <= A <= N; 1 <= B <= N; A != B),都可以找到一个以A开头以B结尾的草地序列,并且序列中相邻的编号所代表的草地相邻。无线电通讯塔只能建在草地上,一座塔的服务范围为它所在的那块草地,以及与那块草地相邻的所有草地。 请你帮FJ计算一下,为了建立能覆盖到所有草地的通信系统,他最少要建多少座无线电通讯塔。

Input

第1行: 1个整数,N

第2..N行: 每行为2个用空格隔开的整数A、B,为两块相邻草地的编号

Output

第1行: 输出1个整数,即FJ最少建立无线电通讯塔的数目

Sample Input

5

1 3

5 2

4 3

3 5

输入说明:

Farmer John的农场中有5块草地:草地1和草地3相邻,草地5和草地2、草地


4和草地3,草地3和草地5也是如此。更形象一些,草地间的位置关系大体如下:

(或是其他类似的形状)

4  2

|  |

1--3--5


Sample Output

2

输出说明:

FJ可以选择在草地2和草地3,或是草地3和草地5上建通讯塔。


HINT

Source

Gold

题解:

1。

之前想成2种状态了,后来发现父亲也可以染。。

dp[i][0]表示以i为根的子树的最小值,且i被它的儿子染。

dp[i][1]表示以i为根的子树的最小值,且选择i。

dp[i][2]表示以i为根的子树的最小值,且i被父亲染。(不能被儿子染)

然后就树上瞎搞。

#include<bits/stdc++.h>
using namespace std;

inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
}

const int N = 10000 + 10;
const int inf = 233333;

int n;
int dp
[3];

struct node{
int pre,v;
}e[N<<1];

int num=0,head
;
void addedge(int from,int to){
e[++num].pre=head[from],head[from]=num;
e[num].v=to;
}

void dfs(int u,int f){
dp[u][0]=inf,dp[u][1]=1;
int sum=0;
for(int i=head[u];i;i=e[i].pre){
int v=e[i].v;
if(v==f) continue;
dfs(v,u);
dp[u][1]+=min(dp[v][0],min(dp[v][1],dp[v][2]));
dp[u][2]+=dp[v][0];
sum+=min(dp[v][0],dp[v][1]);
}
for(int i=head[u];i;i=e[i].pre){
int v=e[i].v;
if(v==f) continue;
dp[u][0]=min(dp[u][0],sum+dp[v][1]-min(dp[v][0],dp[v][1]));
}
}

int main(){
n=read();
for(int i=1;i<n;++i){
int u=read(),v=read();
addedge(u,v);addedge(v,u);
}
dfs(1,0);
printf("%d",min(dp[1][0],dp[1][1]));
return 0;
}


2.贪心。

依旧dfs,每次找到一个点如果它的父亲和它自己和它的兄弟都没有被覆盖到,就把它的父亲覆盖。

其实正确性我不是很会证明……但是感性理解一下,这样每次选择的都是尽可能大的一个范围,所以会很优。

#include<bits/stdc++.h>
using namespace std;

inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=x*10+ch-'0';ch=getchar();}
return x*f;
}

const int N = 10000 + 10;

int n;
int dp
[3];

struct node{
int pre,v;
}e[N<<1];

int num=0,head
;
void addedge(int from,int to){
e[++num].pre=head[from],head[from]=num;
e[num].v=to;
}

int ans=0,vis
;

void dfs(int u,int f){
bool flag=true;
for(int i=head[u];i;i=e[i].pre){
int v=e[i].v;
if(v==f) continue;
dfs(v,u);
if(vis[v]) flag=false;
}
if(flag&&!vis[u]&&!vis[f]) vis[f]=true,++ans;
}

int main(){
memset(vis,0,sizeof(vis));
n=read();
for(int i=1;i<n;++i){
int u=read(),v=read();
addedge(u,v);addedge(v,u);
}
dfs(1,0);
printf("%d\n",ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: