问题 C: [POI2008]枪战Maf

时间限制: 1 Sec  内存限制: 256 MB

题目描述

有n个人,每个人手里有一把手枪。一开始所有人都选定一个人瞄准(有可能瞄准自己)。然后他们按某个顺序开枪,且任意时刻只有一个人开枪。因此,对于不同的开枪顺序,最后死的人也不同。

输入

输入n人数<1000000 每个人的aim

输出

你要求最后死亡数目的最小和最大可能

样例输入

8
2 3 2 2 6 7 8 5

样例输出

3 5

  本次考试最后一个题,被老师评论称难炸了……然而貌似不那么难,但你绝对打不A。

  这道题只能怪我代码能力太弱,该想到的都想到了,然而还是华丽丽的爆了0。

  首先让我们先明确几条性质来帮助我们做题:

    1. 对于每个连通图,他至少有一个环或者一个人自杀。缩完点之后它是树或树林。证明:假设我们已经输入了n个人,先忽略一下第n个人要杀谁,如果之前没有人自杀或环的话它一定是一棵树,因为有n个点和n-1条边,那么第n个人指向哪里就很关键了,他指向每一个其他人都会形成一个环,而指向他自己又是自杀,所以,第一条get。
    2.   每一个没人杀的人都会存活,每一个自杀的人最终都会死。不解释。
    3. 每个人对于答案的影响不在于他被谁杀掉,而在于他杀掉谁,世界不关心你说了什么,世界只关心你做了什么。
    4. 一个环如果没人干预,那么它最少死n/2个人,向下取整。也就是一个人如果不杀人就只能被杀死,对于奇数个点的环你杀了人也可能被杀死。最多就是总人数-1。
    5. 一个环如果有人干预,那么它最多就是全部被杀,最小在下面说。
    6. 如果一个人没死,那么他指向的那个人就一定会死,如果指向那个人的人都死了,那么他就可以活下来,这一点在环中同样适用。

  为了方便,我们直接去求活着的人数,反正人不是活着就是死了废话。

  先说死的人最少,那么入度为0的人一定活下来了,因此我们用队列慢慢往上爬即可,只要队列中的人他所杀的人要杀的人没人杀他了,那么他也可以入队。至于没人指向的环嘛,上面说了。

  死的最多的人就是让人们从树顶从上往下开枪,直到叶子节点所以答案就为缩完点后入度为0的点。

  我打完之后只过了一个点,因为这题有两个坑点,至少对我来说是这样的。

  第一,指向这个点的点可以有好几个,但这个点的出度只有一个,虽然是废话,但在你判断谁存活的时候需要先判断一下,你目前队首的这个点所指向的点是否已经被杀掉,否则错炸了。

  第二,也是卡住了无数英雄好汉的点,如何判断某个环是否已被用队列访问,开个bool记录看似容易,然而在哪里打标记就是大坑了,对于WA的童鞋们可以试一下这个点:

      4

      2 3 2 3

  希望能帮到你们,在这个点中,环中每个人都死了,但如果你在将某个元素塞进队列时才将它打上标记你会发现实际已经访问了的环并未被打上标记,因此,正解是每个被塞进队列的人他所指向的人和他所指向的人所指向的人都要被打上标记。

  

 #include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cmath>
using namespace std;
int n,tt[],st[],top;
bool rz[],rz2[];
int dfn[],low[],zz1;
int zz2,belong[],sum[];
void tar(int x){
zz1++;
top++;
st[top]=x;
rz[x]=rz2[x]=;
dfn[x]=low[x]=zz1;
if(!rz2[tt[x]])
{
tar(tt[x]);
low[x]=min(low[x],low[tt[x]]);
}
else if(rz[tt[x]])
{
low[x]=min(low[x],dfn[tt[x]]);
}
if(dfn[x]==low[x])
{
int v;
zz2++;
do{
v=st[top];
top--;
rz[v]=;
sum[zz2]++;
belong[v]=zz2;
}while(dfn[v]!=low[v]);
}
}
int a[],zz3,rd2[],be[];
bool fw[],js[];
int rd[],ans1,ans2;
queue<int> q1;
int main(){
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d",&tt[i]);
rd[tt[i]]++;
}
for(int i=;i<=n;i++)
if(!rz2[i])
tar(i);
for(int i=;i<=n;i++)
{
if(rd[i]==)
{
ans1++;
q1.push(i);
fw[belong[i]]=;
}
}
while(!q1.empty())
{
int x=q1.front();
q1.pop();
fw[belong[tt[x]]]=;
if(!js[tt[x]])
{
js[tt[x]]=;
rd[tt[tt[x]]]--;
if(rd[tt[tt[x]]]==)
{
ans1++;
fw[belong[tt[tt[x]]]]=;
q1.push(tt[tt[x]]);
}
}
}
for(int i=;i<=zz2;i++)
{
if(!fw[i])
{
ans1+=sum[i]/;
}
}
for(int i=;i<=n;i++)
{
if(belong[tt[i]]!=belong[i]||tt[i]==i)
{
rd2[belong[tt[i]]]++;
}
}
for(int i=;i<=zz2;i++)
{
if(!rd2[i])
ans2++;
}
printf("%d %d",n-ans1,n-ans2);
return ;
}

对了,这道题打法不只一种,有兴趣的读者可以试一试别的方法,DP已被验证可行,贪心据说也可以,希望读者不要拘泥于一种打法。

[POI2008]枪战Maf题解的更多相关文章

  1. 【BZOJ1124】[POI2008]枪战Maf 贪心+思路题

    [BZOJ1124][POI2008]枪战Maf Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开 ...

  2. BZOJ1124 [POI2008]枪战Maf[贪心(证明未完成)+拓扑排序]

    吐槽:扣了几个小时,大致思路是有了,但是贪心的证明就是不会, 死磕了很长时间,不想想了,结果码代码又不会码.. 深深体会到自己码力很差,写很多行还没写对,最后别人代码全一二十行,要哭了 以下可能是个人 ...

  3. BZOJ 1124: [POI2008]枪战Maf

    1124: [POI2008]枪战Maf Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 617  Solved: 236[Submit][Status ...

  4. [POI2008]枪战Maf

    [POI2008]枪战Maf 题目 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的 ...

  5. bzoj 1124 [POI2008]枪战Maf 贪心

    [POI2008]枪战Maf Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 741  Solved: 295[Submit][Status][Disc ...

  6. bzoj1124[POI2008]枪战maf

    这代码快写死我了.....死人最多随便推推结论.死人最少,每个环可以单独考虑,每个环上挂着的每棵树也可以分别考虑.tarjan找出所有环,对环上每个点,求出选它和不选它时以它为根的树的最大独立集(就是 ...

  7. 【BZOJ】1124: [POI2008]枪战Maf

    题意 \(n(n < 1000000)\)个人,每个人\(i\)指向一个人\(p_i\),如果轮到\(i\)了且他没死,则他会将\(p_i\)打死.求一种顺序,问死的人最少和最多的数目. 分析 ...

  8. BZOJ 1124: [POI2008]枪战Maf(构造 + 贪心)

    题意 有 \(n\) 个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪. 因此,对于不同的开枪顺序,最后死的人也不同. 问最 ...

  9. 【BZOJ1124】[POI2008]枪战Maf(基环树_构造)

    被教练勒令做题不能看题解后的第一道新题,自行 yy 了好久终于 AC 了(菜啊)--写博客纪念. 题目: BZOJ1124 分析: 考虑每个人向他要打的人连边.根据题意,所有点都有且只有一条出边.那么 ...

随机推荐

  1. iOS NSString追加字符串的方法

    第一种: NSArray *array = [NSArray arrayWithObjects:@"Hello",@" ",@"world" ...

  2. Oracle报错:不是GROUP BY 表达式

    报错:不是GROUP BY 表达式 实例:select sum(hwjz),rq from JcChargeInfo where 1=1  group by rq order by jcchargec ...

  3. 【转】在C#中简单的科学计算,包括幂数,指数,对数,Math类

    用Math类进行一些简单的科学计算,包括幂数,指数,对数等的计算: double m,n; m=Math.Exp(0.5); //自然对数e的0.5次方 n=Math.Exp(); //自然对数e的3 ...

  4. Zookeeper 部署Zookeeper仲裁模式集群

    部署Zookeeper仲裁模式集群 本例在一台服务器上部署3个zk服务:z1.z2.z3. 1.下载Zookeeper https://zookeeper.apache.org/ 2.解压缩 .tar ...

  5. Windows下用VC与QT编译MPI程序入门

    MPI是信息传递接口的简称,常用来进行进程间.机器间的通信与并行计算.一般而言,MPI都会部署在*nix系统下,在Windows下面直接编译.配置MPI并不容易.本文利用MS提供的编译好的MPI的版本 ...

  6. WPF四年,尤不足以替代WinForm

    WPF四年,尤不足以替代WinForm WPF出山已四年,作为官方内定的下一代UI系统掌门,没少露脸.但这个新掌门能否胜任,仍是众多开发者的心头之虑.通过对VisualStudio 2010的编辑器部 ...

  7. java之继承中的静态变量

    package Test; /** * Created by wangbin10 on 2018/7/9. * 我们知道静态变量属于类级别变量,对应每个类只有一份,类的所有实例共有一份,而成员变量则分 ...

  8. 设置windows服务依赖项

    场景还原:python2.7开发的项目,制作成了windows服务,随系统启动.系统重启后发现服务未能自动启动,检查事件查看器日志发现服务先于Mysql数据库服务启动,由于服务中必须对MySQL进行访 ...

  9. js简单对象List自定义属性排序

    简单对象List自定义属性排序 <script type="text/javascript"> var objectList = new Array(); functi ...

  10. WebFlux 集成 Thymeleaf 、 Mongodb 实践 - Spring Boot(六)

    这是泥瓦匠的第105篇原创 文章工程: JDK 1.8 Maven 3.5.2 Spring Boot 2.1.3.RELEASE 工程名:springboot-webflux-5-thymeleaf ...