【复赛模拟试题】指认坏人 基环外向树+最大独立集
来源:互联网 发布:python3 apache 编辑:程序博客网 时间:2024/05/18 03:51
【问题描述】
n个人中有好人,也有坏人。坏人知道每个人的身份,好人不知道。 现在每个人都指认了一个坏人(没有人会指认自己为坏人),当然,好人基本是乱猜的,而坏人则全部指认的是好人。 那么在不知道谁是坏人的情况下,最多可能有多少坏人。
【输入格式】
输入的第1行包含一个整数n,表示有n个人。这n个人标号为1到n。接下来有n行,每行一个数,其中的第i行表示被第i个人指认的坏人编号。没有谁会指认自己为坏人。
【输出格式】
仅输出一个整数,表示最多可能的坏人的数量。
【输入样例】
【样例1】
3
2
1
1
【样例2】
3
2
3
1
【样例3】
7
3
3
4
5
6
4
4
【输出样例】
【样例1】
2
【样例2】
1
【样例3】
4
【样例解释】
第一个样例解释:杀手可能为2和3;
第二个样例解释:杀手可能是任何1个人,但不可能多于1个,否则杀手就会指认自己人了。
【数据范围】
40%的数据n<25.
80%的数据n<=2000
100%的数据 2<=N<=500000
——————————————————————————————————————————————
分析一下,可以发现这个图不具有连通性。
可以发现图上的边的方向并没有卵用,因为坏人是不可以相互指认的,所以问题变成了选择一个点的集合,使得从这个集合出发的指认不指向这个集合中的任意元素,求集合的元素最多有多少个,如果这是一颗树的话就可以直接做最大独立集了。但是这不一定是一棵树。不过由于每个点只发出一条边可以证明这是一颗基环外向树。然后问题就简单了,找到环上的一条边,dp的时候不经过这条边(我用的dp),同时每一次dp之前要确定这条边的哪边是好人。然后就可以dp了。
再说明一个问题,代码中实际上如果这个环上只有两个点的话找不到这条边就算了,完全没有影响,充其量就是多dp了一次而已。
AC代码:
#include<iostream>#include<cstdio>#include<cstring>#include<cstdlib>#include<algorithm>#include<cmath>#include<queue>#include<set>#include<map>#include<vector>#include<cctype>using namespace std;typedef long long LL;const int maxn=500005;int N;struct edge{ int to,next,id; }E[maxn<<1];int first[maxn],np,ID,s,t;int f[maxn][2],ans;bool vis[maxn];void _scanf(int &x){ x=0; char ch=getchar(); while(ch<'0'||ch>'9') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();}void add_edge(int u,int v,int id){ E[++np]=(edge){v,first[u],id}; first[u]=np;}void data_in(){ _scanf(N); int x; for(int i=1;i<=N;i++) { _scanf(x); add_edge(x,i,i); add_edge(i,x,i); }}void DFS(int i,int fa){ vis[i]=1; for(int p=first[i];p;p=E[p].next) { int j=E[p].to; if(vis[j]) { if(j!=fa) ID=E[p].id,s=i,t=E[p].to; continue; } DFS(j,i); }}void DFS(int i,int fa,int nc){ f[i][0]=f[i][1]=0; if(i!=nc) f[i][1]=1; for(int p=first[i];p;p=E[p].next) { if(ID==E[p].id) continue; int j=E[p].to; if(j==fa) continue; DFS(j,i,nc); f[i][0]+=max(f[j][0],f[j][1]); if(i!=nc) f[i][1]+=f[j][0]; }}void work(){ for(int i=1;i<=N;i++) if(!vis[i]) { DFS(i,0); DFS(i,0,s); int tmp=max(f[i][0],f[i][1]); DFS(i,0,t); tmp=max(tmp,max(f[i][0],f[i][1])); ans+=tmp; } printf("%d\n",ans);}int main(){ freopen("badperson.in","r",stdin); freopen("badperson.out","w",stdout); data_in(); work(); return 0;}
- 【复赛模拟试题】指认坏人 基环外向树+最大独立集
- CQYZ【复赛模拟题】指认坏人+【zjoi2008】骑士
- codeforces—Royal Questions(并查集维护最大基环外向树)
- 【复赛模拟试题】求和
- 【复赛模拟试题】收费站
- 【复赛模拟试题】河床
- 基环外向树dp
- 【复赛模拟试题】计数排序
- 【复赛模拟试题】 物品选取
- 【复赛模拟试题】学生公寓 贪心
- 【bzoj1040】骑士 基环外向树 树规
- 【复赛模拟试题】书的排序
- 【复赛模拟试题】盛夏的果实
- 【复赛模拟试题】寿司 中位数思想
- 【复赛模拟试题】新斯诺克 逆序对
- 【复赛模拟试题】奶牛卧室 筛法
- 树的最大独立集
- 树的最大独立集
- paramiko基本方法
- C++ STL开发温习与总结(三): 3.C++函数技术
- Linux上MySQL的root密码忘记
- 猴子测试--步骤
- CentOS7.0安装配置hadoop2.7.0 资源准备 资源下载: hadoop-2.7.0.tar.gz 密码:727y jdk-8u45-linux-x64.tar.gz 密码:d8bm
- 【复赛模拟试题】指认坏人 基环外向树+最大独立集
- 设置eclipse查看java源码
- hibernate--14.结果接受
- SGISTL源码探究-stl_algo.h中的基础算法
- 玲珑杯 1097题 LIS(最长递增子序列)
- java爬虫之登录到教务系统抓取成绩
- Android 集成环信即时通讯修改用户密码
- 对于TomCat端口被占用问题
- ARM裸机编程需要知道的汇编知识2---哈弗结构和冯诺依曼结构