码迷,mamicode.com
首页 > 其他好文 > 详细

枪战Maf (bzoj 1124)

时间:2018-10-04 08:59:43      阅读:215      评论:0      收藏:0      [点我收藏+]

标签:疑问   分享   for   开始   include   mic   output   std   png   

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 的点【绿框】必定存活,那么他所指的点【红圈】必定会死(早晚的事)。所以没有一个“绿框”,我们就:mx++,mn++; //这,毫无疑问
 
我们可以发现:
  • 如果 2 死之前射死了他指的人,那么 mn 不变
  • 如果 2 先死了,3 的入度--,他的入度变为了 0 ,进队;当然 3 也有可能入读不为 0,那么它必定会构成环或链,想要尽量活的人多,那就要这个环或链隔一个人,打一个,最多就可以存活 len/2 个人
 
code
#include<stdio.h>
#include<queue>
#include<algorithm>
using namespace std;
const int MX=1000001;
int n,mx,mn,q[MX],aim[MX],indu[MX];
bool die[MX],undie[MX];

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i) {
        scanf("%d",&aim[i]);
        indu[aim[i]]++;
    }
    for(int i=1;i<=n;++i) if(indu[i]==0) mn++,q[++mx]=i;
    int head=1;
    while(head<=mx)
    {
        int cur=q[head];head++;
        if(die[aim[cur]]) continue;
        die[aim[cur]]=1;
        int live=aim[aim[cur]];
        indu[live]--;
        undie[live]=1;
        if(indu[live]==0) q[++mx]=live;
    }
    for(int i=1;i<=n;++i) if(indu[i] && !die[i]) {
        int len=0,flag=0;    
        for(int j=i;!die[j];j=aim[j]) {
            len++;
            flag|=undie[j];
            die[j]=1;
        }
        if(!flag && len>1) mn++;
        mx+=len/2;
    } 
    printf("%d %d",n-mx,n-mn);
    return 0;
} 

 

 

枪战Maf (bzoj 1124)

标签:疑问   分享   for   开始   include   mic   output   std   png   

原文地址:https://www.cnblogs.com/qseer/p/9740930.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!