大地的复苏

大地的复苏

 时间限制: 1 s
 空间限制: 64000 KB
题目描述 Description

  萌萌哒tangjz感应到OI村遭到了坏人Kinger Tangent的侵袭,急急忙忙的又赶了回来。 T_T

  目前局势非常不好,Kinger Tangent正在施法引出岩浆不便移动,所以tangjz准备在一些地方布下防御塔。

  现在的OI村有N个高地,编号分别为1~N。

  萌萌哒tangjz布下的神の防御塔有着正义力量的加成,除了保护该地点外,还强制额外庇护另外一个地点,不过如果额外能庇护的地点已经受到保护了,就不能再该地点布置防御塔,否则会由于能量过大造成毁灭(不论主动被动,每个地点只能被庇护一次)。 >_<

输入描述 Input Description

  第一行一个正整数N,表示OI村高地个数。

  第二行有N个正整数,第i个正整数表示在第i个高地建立防御塔可以额外庇护的地点。

输出描述 Output Description

  最多可以建的防御塔个数。

样例输入 Sample Input

10
4 5 5 2 3 7 8 9 10 9

样例输出 Sample Output

4

数据范围及提示 Data Size & Hint

对于30%的数据:
对于60%的数据:
对于100%的数据:每个地点都可以庇护一个其他的地点

题目链接:http://codevs.cn/problem/2820/


拓扑排序+贪心。瞎搞了好久的动态规划。。。。。首先分析偶数链在环上的情况,如果贪心的选择链尾的最后一个点,发现选择到最后不会影响环上的点,如果是奇数链在环上,则最后一个选择的点一定会影响到环上的点,因此我们此时要对环进行继续贪心。如果在对环进行贪心的时候发现环上某个点还连着某一条链,如果是偶数链则没有影响,如果是奇数链,发现我们要是选了这个点,环上贡献加一,但是链上贡献减一,如果不选这个点,环上贡献减一,链上贡献加一,因此表面上看选不选这个点对答案没有影响,其实不然,如果选了这个点,环上这个点的下一个点就不能选了,如果不选这个点,这个点的下一个点还可以选。因此贪心的考虑我们不能选这个点。以上操作可以通过拓扑排序完美完成。

#include<bits/stdc++.h>
#define N 2000000
int next[N],ind[N],vis[N],q[N];
int main()
{
    int n,i,ans=0;
    scanf("%d",&n);
    for(i=1;i<=n;i++)
    {
        scanf("%d",&next[i]);
        ind[next[i]]++;
    }
    int x,tot=0;
    for(i=1;i<=n;i++)
     if(ind[i]==0)q[++tot]=i;

    while(tot)
    {
        int now=q[tot--],nex=next[now];
        vis[now]=true;
        if(!vis[nex])
        {
            vis[nex]=true;
            ans++;
            if(!vis[next[nex]]&&(--ind[next[nex]]==0))
            q[++tot]=next[nex];
        }
    }

    for(i=1;i<=n;i++)
    if(!vis[i])
     {
         int now=i,nex=i,c=1;
         vis[i]=true;
         while(1)
         {
             nex=next[nex];
             if(nex==now)
             {
                 ans+=c/2;
                 break;
             }
             else
             {
                 c++;
                 vis[nex]=true;
             }
         }
     }
    printf("%d",ans);
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/tian-luo/p/9746162.html