BZOJ 1124 POI2008 枪战Maf 贪心

来源:互联网 发布:淘宝如何拆分订单 编辑:程序博客网 时间:2024/04/27 17:47

题目大意:给定n个神枪手,每个神枪手瞄准一个人,以一定顺序开枪,问最少和最多死多少人

首先考虑最多
对于每个联通块:
如果这个连通块只有一个人,那么这个人自杀,死亡人数为1
如果这个连通块是一个环,那么可以活下来一个人,死亡人数为size1
否则除了叶节点之外其他人都可以死,死亡人数为sizecnt

接下来考虑最少
首先叶节点一定不能死
首先把叶节点加入队列,然后每取出一个点时,击杀他瞄准的人,然后如果他瞄准的人瞄准的人此时成为了一个叶节点,那么把这个人加入队列
最后会剩下一些环,一个大小为size的环死亡人数为size2

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 1001001using 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;}
0 0
原创粉丝点击