题目大意:给定
首先考虑最多
对于每个联通块:
如果这个连通块只有一个人,那么这个人自杀,死亡人数为
如果这个连通块是一个环,那么可以活下来一个人,死亡人数为
否则除了叶节点之外其他人都可以死,死亡人数为
接下来考虑最少
首先叶节点一定不能死
首先把叶节点加入队列,然后每取出一个点时,击杀他瞄准的人,然后如果他瞄准的人瞄准的人此时成为了一个叶节点,那么把这个人加入队列
最后会剩下一些环,一个大小为
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 1001001
using namespace std;
int n,ans1,ans2;
int a[M],degree[M];
namespace Solver1{
int degree[M];
bool v[M],dead[M];
void Solve()
{
static int q[M],r,h;
int i;
memcpy(degree,::degree,sizeof degree);
for(i=1;i<=n;i++)
if(!degree[i])
q[++r]=i;
while(r!=h)
{
int x=q[++h];
v[x]=true;
if(!dead[a[x]])
{
v[a[x]]=dead[a[x]]=true;ans1++;
if( !--degree[a[a[x]]] )
q[++r]=a[a[x]];
}
}
for(i=1;i<=n;i++)
if(!v[i])
{
int cnt=0,x=i;
while(1)
{
if(v[x]) break ;
v[x]=true;cnt++;
x=a[x];
}
ans1+=cnt+1>>1;
}
}
}
namespace Solver2{
struct abcd{
int to,next;
}table[M<<1];
int head[M],tot;
bool v[M];
int stack[M],top;
void Add(int x,int y)
{
table[++tot].to=y;
table[tot].next=head[x];
head[x]=tot;
}
void BFS(int x)
{
static int q[M],r,h;
int i;
q[++r]=x;v[x]=true;
while(r!=h)
{
x=q[++h];
stack[++top]=x;
for(i=head[x];i;i=table[i].next)
if(!v[table[i].to])
v[table[i].to]=true,q[++r]=table[i].to;
}
}
void Solve()
{
int i;
for(i=1;i<=n;i++)
{
Add(i,a[i]);
Add(a[i],i);
}
for(i=1;i<=n;i++)
if(!v[i])
{
top=0;
BFS(i);
if(top==1)
ans2++;
else
{
int cnt=0,size=top;
while(top)
cnt+=degree[stack[top--]]==0;
if(cnt==0)
ans2+=size-1;
else
ans2+=size-cnt;
}
}
}
}
int main()
{
int i;
cin>>n;
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
degree[a[i]]++;
}
Solver1::Solve();
Solver2::Solve();
cout<<ans1<<‘ ‘<<ans2<<endl;
return 0;
}
原文地址:http://blog.csdn.net/popoqqq/article/details/46593377