您的位置:首页 > 其它

珠海邀请赛个人解题报告 Problem E: Cinema

2010-10-30 14:10 344 查看
Problem E: Cinema

Description
There are N universities in the city of ZhuHai, numbered from 1 to n. These universities are connected by N-1 roads and any two universities reachable. A part of universities connected by a single road are called “adjacent”. You’re the manager of a nationwide-famous cinema -- Joy Luck Union Cinema, who is planning to build a series of cinemas in the universities in Zhu Hai to serve the College students. However, college students are busy, so they only want to watch movies in their own campus or “adjacent” campus. As we all know,building a cinema is costly. You want to save expense buy you also want to serve all students. Therefore you have to decide what is the minimum number of JLU cinemas to be built, so that for a student of any campuses, at least one JLU cinema is accessible?
Input
There are multiple test cases in the input. Each test case starts with a line containing an integer N (0<N<=10000), indicating the number of universities. Then n-1 lines follows, each of which contains two integers A and B, representing A and B are connected by a road.
Output
For each test case, print the minimum amount of cinemas you should built in a single line.

Sample Input
6
1 2
2 4
3 6
5 3
3 2
3
2 1
1 3
Sample Output
2
1

这道题挺悲剧的,当时比赛的时候卡死在上面了...
这道题大概的题意是,在有N个节点的树 G(V,E) 上选择m个节点v属于V,设为集合S,使得V中任意一个节点可以通过<=1 的边到达S中的节点。求m的最小值。
这道题可以用贪心来解决。
这道题是一道典型的树型DP的题目,其原型是 Party at Hali-Bula :原型的贪心解法如下
1、找到一个编号最小的叶子结点(对于这题也就是度为0的点),在其父结点放置一个电影院, 删除所有与其父节点相连的边
2、重复1直到删光所有的边
其树型DP的做法为:
dproot[i]表示以 i 为根的子树,在 i 上面设置一个士兵, 完成整个子树需要多少个士兵
p[i] 表示看守整个以 i 为根的子树需要设置多少个士兵;
状态转移方程:
叶子节点 : dproot[i] = 1 , p[i] = 0;
非叶子节点:dproot[i] = 1 + Σp[j] (其中 j 是 i 的儿子)
对于本题而言,将一个点看守边变成了看守相邻的点,可以用类似的方法建立方程。
#include<iostream>
#include <vector>
using namespace std;
const int MAXN = 10001 ;
int n,res,num[MAXN],flag[MAXN],par[MAXN];//num用来记录每个节点有多少个枝干,flag搜索的标记数组
//其中,par数组用来存储每个节点的子父关系,这里可以比较好的提高搜索的效率
vector <int> list[MAXN];//邻接表
void build(int now)//将树的邻接表转换为子父关系的数组
{
int i;
for(i=0;i<num[now];i++)
if(list[now][i]!=par[now])
{
par[list[now][i]]=now;
build(list[now][i]);
}
}
void search(int now)
{
int j=0;
for(int i=0;i<num[now];i++)
{
if(list[now][i]!=par[now])
{
search(list[now][i]);
if(flag[list[now][i]]==0) j=1;
}
}
if(j==1)
{
res++;
flag[now]=1;
for(int i=0;i<num[now];i++)
flag[list[now][i]]=1;
}
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
int k,j;
for(int i=1;i<=n;i++)
{
list[i].clear();
par[i]=flag[i]=0;
}
for(int i=1;i<n;i++)
{
scanf("%d%d",&k,&j);
list[k].push_back(j);
list[j].push_back(k);
}
for(int i=1;i<=n;i++) num[i]=list[i].size();
build(1); res=0;
search(1);
if(flag[1]==0) res++;
printf("%d/n",res);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: