[POI2008]枪战Maf题解

   

问题 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

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

  

  1 #include<iostream>
  2 #include<cstdlib>
  3 #include<cstdio>
  4 #include<cstring>
  5 #include<queue>
  6 #include<algorithm>
  7 #include<cmath>
  8 using namespace std;
  9 int n,tt[1000004],st[1000005],top;
 10 bool rz[1000005],rz2[1000005];
 11 int dfn[1000005],low[1000005],zz1;
 12 int zz2,belong[1000005],sum[1000005];
 13 void tar(int x){
 14     zz1++;
 15     top++;
 16     st[top]=x;
 17     rz[x]=rz2[x]=1;
 18     dfn[x]=low[x]=zz1;
 19     if(!rz2[tt[x]])
 20     {
 21         tar(tt[x]);
 22         low[x]=min(low[x],low[tt[x]]);
 23     }
 24     else if(rz[tt[x]])
 25     {
 26         low[x]=min(low[x],dfn[tt[x]]);
 27     }
 28     if(dfn[x]==low[x])
 29     {
 30         int v;
 31         zz2++;
 32         do{
 33             v=st[top];
 34             top--;
 35             rz[v]=0;
 36             sum[zz2]++;
 37             belong[v]=zz2;
 38         }while(dfn[v]!=low[v]);
 39     }
 40 }
 41 int a[1000005],zz3,rd2[1000006],be[1000005];
 42 bool fw[1000005],js[1000005];
 43 int rd[1000005],ans1,ans2;
 44 queue<int> q1;
 45 int main(){
 46     scanf("%d",&n);
 47     for(int i=1;i<=n;i++)
 48     {
 49         scanf("%d",&tt[i]);
 50         rd[tt[i]]++;
 51     }
 52     for(int i=1;i<=n;i++)
 53         if(!rz2[i])
 54             tar(i);
 55     for(int i=1;i<=n;i++)
 56     {
 57         if(rd[i]==0)
 58         {
 59             ans1++;
 60             q1.push(i);
 61             fw[belong[i]]=1;
 62         }
 63     }
 64     while(!q1.empty())
 65     {
 66         int x=q1.front();
 67         q1.pop();
 68         fw[belong[tt[x]]]=1;
 69         if(!js[tt[x]])
 70         {
 71             js[tt[x]]=1;
 72             rd[tt[tt[x]]]--;
 73             if(rd[tt[tt[x]]]==0)
 74             {
 75                 ans1++;
 76                 fw[belong[tt[tt[x]]]]=1;
 77                 q1.push(tt[tt[x]]);
 78             }
 79         }
 80     }
 81     for(int i=1;i<=zz2;i++)
 82     {
 83         if(!fw[i])
 84         {
 85             ans1+=sum[i]/2;
 86         }
 87     }
 88     for(int i=1;i<=n;i++)
 89     {
 90         if(belong[tt[i]]!=belong[i]||tt[i]==i)
 91         {
 92             rd2[belong[tt[i]]]++;
 93         }
 94     }
 95     for(int i=1;i<=zz2;i++)
 96     {
 97         if(!rd2[i])
 98             ans2++;
 99     }
100     printf("%d %d",n-ans1,n-ans2);
101     return 0;
102 }
103  

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

时间: 2024-10-19 21:02:16

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

BZOJ1124: [POI2008]枪战Maf

1124: [POI2008]枪战Maf Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 501  Solved: 200[Submit][Status][Discuss] Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的人也不同. Input 输入n人数<1000000 每个人的aim Output 你要求最

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

[BZOJ1124][POI2008]枪战Maf Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的人也不同. Input 输入n人数<1000000 每个人的aim Output 你要求最后死亡数目的最小和最大可能 Sample Input 8 2 3 2 2 6 7 8 5 Sample Output 3 5 题解:最大:首先入度为0的点一定不会死:另外,

BZOJ 1124: [POI2008]枪战Maf

1124: [POI2008]枪战Maf Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 617  Solved: 236[Submit][Status][Discuss] Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的人也不同. Input 输入n人数<1000000 每个人的aim Output 你要求最

bzoj1124[POI2008]枪战maf tarjan+树规+贪心/线性DP

这代码快写死我了.....死人最多随便推推结论.死人最少,每个环可以单独考虑,每个环上挂着的每棵树也可以分别考虑.tarjan找出所有环,对环上每个点,求出选它和不选它时以它为根的树的最大独立集(就是最多活下来的人数),然后环上每个点选或不选对应的是一个“价值”,这个价值是那个点挂着的树里最多存活人数.先全都不选环上的点,算出选和不选时最大独立集的差值,问题变成有一个环,环上有一堆数(那些差值),选出一些不相邻的数使得和最大,然后我按着bzoj2151种树写了个贪心....这个贪心的思路也很神,

BZOJ 1124 POI2008 枪战Maf 贪心

题目大意:给定n个神枪手,每个神枪手瞄准一个人,以一定顺序开枪,问最少和最多死多少人 首先考虑最多 对于每个联通块: 如果这个连通块只有一个人,那么这个人自杀,死亡人数为1 如果这个连通块是一个环,那么可以活下来一个人,死亡人数为size?1 否则除了叶节点之外其他人都可以死,死亡人数为size?cnt叶节点 接下来考虑最少 首先叶节点一定不能死 首先把叶节点加入队列,然后每取出一个点时,击杀他瞄准的人,然后如果他瞄准的人瞄准的人此时成为了一个叶节点,那么把这个人加入队列 最后会剩下一些环,一个

BZOJ 1124[POI2008]枪战

题面: 1124: [POI2008]枪战Maf Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 659  Solved: 259[Submit][Status][Discuss] Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的人也不同. Input 输入n人数<1000000 每个人的aim Output

枪战Maf[POI2008]

题目描述 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的人也不同. 输入 输入n人数<1000000 每个人的aim 输出 你要求最后死亡数目的最小和最大可能 样例输入 8 2 3 2 2 6 7 8 5 样例输出 3 5 题解 这道题--说来话长了这就.考试的时候,一画样例明显是个图论题,出了环明显要缩点,缩了点明显还有一堆什么玩意,打着打着就忘了还有疯子自杀来着= =.不算自

枪战Maf (bzoj 1124)

Description 有n个人,每个人手里有一把手枪.一开始所有人都选定一个人瞄准(有可能瞄准自己).然后他们按某个顺序开枪,且任意时刻只有一个人开枪.因此,对于不同的开枪顺序,最后死的人也不同. Input 输入n人数<1000000 每个人的aim Output 你要求最后死亡数目的最小和最大可能 Sample Input 8 2 3 2 2 6 7 8 5 Sample Output 3 5 解析拓扑 设最大存活人数 mx,最少存活人数 mn 如图,入度为 0 的点[绿框]必定存活,那么

暑假集训D9总结

考试 几乎绝望的考试= =,感觉自己啥都打不出来= =,就一道DP打了个贪心,剩下两道骗分,然而竟然排到前一半= =,不可思议= = 真是令人窒息的操作啊= = T1  [bzoj1592] Making the Grade T2  [Usaco2007 Open]Fliptile 翻格子游戏 T3  [POI2008]枪战Maf 博客 github成功炸掉了,呜呜呜 然后我就搞了一晚上+半个早晨的补档= = 顺便导致了这篇D9的总结只能在D10扔出来 令人绝望啊 生活 我已经快GG了= = 退