BZOJ1124: [POI2008]枪战Maf

1124: [POI2008]枪战Maf

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 501  Solved: 200
[Submit][Status][Discuss]

Description

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

Input

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

Output

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

Sample Input

8
2 3 2 2 6 7 8 5

Sample Output

3 5

HINT

 

Source

题解:思路好题;

最小:对于一个入度为0的点,它所指的点一定会死,

   于是删除此点及其边,在找入度为0的点,成为子问题,

   然后只剩下环,画图发现环的答案为size/2;

最大:对于一条链或者一链+一环都之后剩下一个为死【入度为0的点】

   对于一个环也只会留下一个!

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#define N 1000010
using namespace std;
int n,i,j,ans1,ans2,len,h,bo;
int die[N],undie[N],q[N],a[N],in[N];
int read()
{
    int x=0,f=1; char ch;
    while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') f=-1;
    while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9');
    return x*f;
 } 
int main()
{
    n=read();
    for (int i=1; i<=n; i++) a[i]=read(),in[a[i]]++;
    for (int i=1; i<=n; i++)
    {
        if (in[i]==0) ans1++,q[++ans2]=i;
    }
    for (int h=1; h<=ans2; h++)
    {
        int i=a[q[h]];
        if (die[i]) continue;
        die[i]=1; undie[a[i]]=1;
        --in[a[i]];
        if (in[a[i]]==0) q[++ans2]=a[i];
    }
    for (int i=1; i<=n; i++)
    if (in[i]&&!die[i])
    {
        len=bo=0;
        for (int j=i; !die[j]; j=a[j])
        {
            die[j]=1; ++len;
            bo|=undie[j];
        }
        if (!bo&&len>1) ++ans1;
        ans2+=len/2;
    }
    printf("%d %d\n",n-ans2,n-ans1);
    return 0;
}
View Code

 

posted @ 2016-08-21 22:27  ACist  阅读(865)  评论(3编辑  收藏  举报