原题链接:蓝桥杯算法提高VIP-传染病控制
解题思路:
注意事项:
参考代码:
九十多行代码:
#include<iostream>
#include<cstdio>
using namespace std;
struct node
{
int next[1000];//与该点相邻的点(建树前用)
int dep;//该点深度(建树后用)
int nextnum;//与该点相邻的点的数量(建树前用)
int father;//该点的父亲(建树后用)
}tree[1000];//保存树的信息
int n,p,y,x,numd[10000],maxdep,depth[1000][1000],minn=99999;
bool f[401],ff[401],pd;
bool find(int x)
{
if (x==1)//如果已经找到顶了,说明这一条路径上都没有之前没剪过的树枝
{
pd=false;//打个标记
return true;
}
if (!ff[tree[x].father]||tree[x].father==1)
find(tree[x].father);
if (pd) return false;
else return true;
}
//找当前边的祖先是否被剪过
void dfs(int x,int d)
{ tree[x].dep=d;
++numd[d];//numd保存深度为d的点的个数
depth[d][numd[d]]=x;//depth[d][i]表示深度为d的第i个点是什么
maxdep=max(maxdep,d);
int i;
for (i=1;i<=tree[x].nextnum;++i)
{
if (f[tree[x].next[i]]) continue;//不能当前点的父亲当他的儿子(有点绕)
tree[tree[x].next[i]].father=x;
f[tree[x].next[i]]=true;
dfs(tree[x].next[i],d+1);
}
}
//建树
void doit(int d,int ans)
{
if (ans>minn)//如果感染人数已经超过之前的最小答案了,不用做了,反正没意义
return;
int i,j;
if (d==maxdep+1)//如果所有层都搜完了,更新答案
minn=min(minn,ans);
else
{
int hh=0;
for (i=1;i<=numd[d];++i)//找当前层有几个没被感染的
{
pd=true;
if (find(depth[d][i]))
{
++hh;
ff[depth[d][i]]=false;
}
else
ff[depth[d][i]]=true;
}
if (hh==0)//如果当前全部都被保住了,就更新答案然后返回到上一层
{
minn=min(minn,ans);
return;
}
for (i=1;i<=numd[d];++i)//当前层一个人一个人的依次救试试
{
if (ff[depth[d][i]])
continue;
ff[depth[d][i]]=true;
doit(d+1,ans+hh-1);
ff[depth[d][i]]=false;
}
}
}
//每层枚举要剪的树枝然后剪掉,搜下一层。注意如果祖先被剪过则该树枝不能剪
int main()
{
scanf("%d%d",&n,&p);
for (int i=1;i<=p;++i)
{
scanf("%d%d",&x,&y);
tree[x].next[++tree[x].nextnum]=y;
tree[y].next[++tree[y].nextnum]=x;
}
f[1]=true;
tree[1].father=1;
dfs(1,1);
doit(1,1);
printf("%d",minn);
}0.0分
5 人评分
C语言网提供由在职研发工程师或ACM蓝桥杯竞赛优秀选手录制的视频教程,并配有习题和答疑,点击了解:
一点编程也不会写的:零基础C语言学练课程
解决困扰你多年的C语言疑难杂症特性的C语言进阶课程
从零到写出一个爬虫的Python编程课程
只会语法写不出代码?手把手带你写100个编程真题的编程百练课程
信息学奥赛或C++选手的 必学C++课程
蓝桥杯ACM、信息学奥赛的必学课程:算法竞赛课入门课程
手把手讲解近五年真题的蓝桥杯辅导课程
发表评论 取消回复