问题 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. wpf 事件参数 绑定到viewmdoel

    public sealed class EventCommand : TriggerAction<DependencyObject> { public static readonly De ...

  2. Quora的技术探索

    关于问答类的应用,最早接触的是stackoverflow和知乎 ,而Quora作为知乎的原型,因为其创始人来自FaceBook而吸引了我.事实上关于Quora的技术分析,冯大辉和陈皓都已经有所详细的阐 ...

  3. iOS 自定义UIButton

    工作中有一个点击button更新button上文案的需求,用自定义了button可以很简单的实现的这个需求 首先写个自定义的button CustomButton.h #import <UIKi ...

  4. SFC游戏列表(维基百科)

    SFC游戏列表 日文名 中文译名 英文版名 发行日期 发行商 スーパーマリオワールド 超级马里奥世界 Super Mario World 1990年11月21日 任天堂 エフゼロ F-Zero F-Z ...

  5. msys2 安装笔记(可以按照这个关键字搜索)

    以前一直在用 msys,最近发现还有个 msys2,并且msys2 配套的编译器是MinGW-w64. 就试着用了用,感觉还不错,这里把安装过程记录一下. 简单的说,MSYS2 是MSYS的一个升级版 ...

  6. Linux SD卡建立两个分区

    本文主要介绍Linux 环境下 SD 卡建立两个分区的操作流程: 操作环境:Linux Ubuntu 2016.4 操作目的:将 SD 卡分为两个分区:第一分区格式为 FAT32,大小 500M.第二 ...

  7. Delphi使用android的NDK是通过JNI接口,封装好了,不用自己写本地代码,直接调用

    一.Android平台编程方式:      1.基于Android SDK进行开发的第三方应用都必须使用Java语言(Android的SDK基于Java实现)      2.自从ndk r5发布以后, ...

  8. Color gradient in Delphi FireMonkey

    Introduction to color gradients in Delphi FireMonkey. Video This video covers the basics of color gr ...

  9. 32个Python爬虫项目让你一次吃到撑

    整理了32个Python爬虫项目.整理的原因是,爬虫入门简单快速,也非常适合新入门的小伙伴培养信心.所有链接指向GitHub,祝大家玩的愉快~O(∩_∩)O WechatSogou [1]- 微信公众 ...

  10. java关键字-interface

    1:是用关键字interface定义的. 2:接口中包含的成员,最常见的有全局常量.抽象方法. 注意:接口中的成员都有固定的修饰符. 成员变量:public static final 成员方法:pub ...