题目大意:给定n个神枪手,每个神枪手瞄准一个人,以一定顺序开枪,问最少和最多死多少人
题解:
首先考虑无环的情况,对图分层,入度为0为1层,必定存活
存活最多:奇数层存活
存活最少:只有第一层存活
考虑有环
存活最多:画图发现环的答案为len/2
存活最少:只剩下1个
注意:在程序中统计的是存活的最大,最小人数,输出时用n减去即可
我的收获:思路强啊
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
#define M 1000010
int n,mi,mx,len,h,bo;//mi表示存活最少,mx表示存活最多
int a[M],q[M],in[M];
bool die[M],undie[M];
void work()
{
for(int h=1;h<=mx;h++)
{
int u=q[h],x=a[u];
if(die[x]) continue;
die[x]=1;undie[a[x]]=1;
--in[a[x]];
if(!in[a[x]]) q[++mx]=a[x];//再找入度为0的点,继续
}
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];//环上必须全部die才可以
}
if(!bo&&len>1) ++mi;
mx+=len/2;
}
printf("%d %d\n",n-mx,n-mi);
}
void init()
{
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]),in[a[i]]++;//a[i]表示i瞄准的人
for(int i=1;i<=n;i++) if(!in[i]) mi++,q[++mx]=i,undie[i]=1;//入度为0的点存活
}
int main()
{
init();
work();
return 0;
}