这个问题是我乱命名的
最小驻扎指的是:
图上每个点,可以付出代价并对其周围一定距离的点产生影响。
求最小的驻扎量,使得所有的点受影响。
又强行编了个定义
解决这类问题的方法,我知道两种
- 动态规划
- 贪心
DP太难了我不会,我只会贪心。
直接讲难的吧(反正简单的改一下就可以了
狗屎测试题。
先讲思路(我抄袭的,from zt
对于最深的点,要想让它被控制,最优(不仅控制它,还可以控制尽量多的其他点)的方案一定是它的第k父亲。
以深度排序,从最深的开始检查:如果该点没有被控制,就在它的第k父亲放军队,并更新第k父亲可以影响到的点的状态。
虽然很暴力,但这是对的。
大家颅内证明一下
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int n,k,t;
vector <int> map[100001];//存图
struct yi//存点
{
int posi;//点的编号
int deep;//点的深度
friend bool operator < (const yi &a,const yi &b)
{
return a.deep>b.deep;//重载 < 排序用
}
}point[100001];//也可以写node[100001];
bool vis[100001];//是否访问过
int shen[100001];//存编号i的深度。和point[].deep一样,但这个从1~n方便用。
void dfs(int x,int d)//dfs求深度。x表示当前点,d表示当前点深度
{
vis[x]=1;//标记,访问过了
point[x].posi=x,point[x].deep=d;//存下编号及深度
for(unsigned int i=0;i<map[x].size();i++)
if(!vis[map[x][i]])//避免重复求
dfs(map[x][i],d+1);
}
bool control[100001];//是否被控制
bool cmp1(const int &a,const int &b)
{
return shen[a]<shen[b];//find()排序用的比较
}
inline int find(int x,int d)//查找最深节点的第k父亲。d最开始调用为k,不断-1,=0时走到第k父亲
{
if(!d)
return x;
vis[x]=1;
sort(map[x].begin(),map[x].end(),cmp1);//排序,原因请下拉
for(unsigned int i=0;i<map[x].size();i++)
if(!vis[map[x][i]])
return find(map[x][i],d-1);//dfs找下去
return x;//找不到,即没有第k父亲,只有第k-1父亲或k-2或...,返回本节点代替第k父亲
}
inline void change(int x,int d)//改变可影响到的节点的状态control[]
{
control[x]=1;//已控制
if(!d)//d递减进行dfs
return ;
vis[x]=1;//标记访问过
for(unsigned int i=0;i<map[x].size();i++)
if(!vis[map[x][i]])
change(map[x][i],d-1);
}
int main()
{
in(n);in(k);in(t);
if(k==0)//特别判断垃圾情况,k==0每个点只能控制自己
{
cout<<n;
return 0;
}
int ans=0;
for(int i=1;i<n;i++)
{
int x,y;
in(x);in(y);
map[x].push_back(y);
map[y].push_back(x);//vector最高
}
dfs((1+n)>>1,1);//求深度的起点可以随意,我选择(1+n)>>1
sort(point+1,point+n+1);//从1开始存的
for(int i=1;i<=n;i++)
shen[point[i].posi]=point[i].deep;//预先用shen[]存好节点深度,方便找 排序
for(int i=1;i<=n;i++)
if(!control[point[i].posi])//如果当前最深点没被控制
{
memset(vis,0,sizeof(vis));//初始化
int dad=find(point[i].posi,k);//找第k父亲。懒得想变量名,直接dad
memset(vis,0,sizeof(vis));//初始化
change(dad,k);//更新状态
ans++;//更新答案
}
cout<<ans;
return 0;
}
sort的原因
bool cmp1(const int &a,const int &b)
{
return shen[a]<shen[b];
}
inline int find(int x,int d)
{
if(!d)
return x;
vis[x]=1;
sort(map[x].begin(),map[x].end(),cmp1);
for(unsigned int i=0;i<map[x].size();i++)
if(!vis[map[x][i]])
return find(map[x][i],d-1);
return x;
}
我们从最深的节点开始找第k父亲。但在树上(这题),一个点的第k父亲,可能不止一个,我们只选择最优的贪心。最优的第k父亲,一定是深度最小的第k父亲。因为贪心的目的就是由深到浅进行控制,越早控制浅的就越优,所以进行排序,对深度最浅的进行dfs找第k父亲。
然后就A啦。
视奸dalao的不同写法的代码
还有好多,全部放下来的话下拉体验很差
修改一下输入方法,这题也轻松A