WOJ 29 Werewolf(树形DP+枚举)

来源:互联网 发布:淘宝申诉进货发票凭证 编辑:程序博客网 时间:2024/06/06 05:53

Input file: standard inputOutput file: standard output Time limit: 1 secondMemory limit: 512 mebibytes

Generally, ACMers play Werewolf game anywhere when they go out for any programming contests. There are several roles in this game, including werewolves, villagers, seer, witch, hunter, cupid……

Here is the rule of the game:

The werewolves Each night the werewolves kill a player.

The villagers The villagers has no skills.

The seer Each night the seer can look at a card of a player of his choice to find out the real.

The hunter If the hunter gets killed, the hunter has the power to retaliate by killing a player of his choice immediately.

The cupid On the first night, cupid picks 2 players who he denotes as lovers. Those 2 players will fall madly in love with each another. If one of the lover dies, the other, out of sadness, dies immediately.

The witch The witch knows how to make up 2 extremely powerful potions. One healing potion, which can revive the player that has been killed by the werewolves. One poison potion, which when used at night can kill a player. The witch must use each potion only once during the game.

...

After each night, everyone wakes up, the god(game master) shows all players which player was killed during the night. After discussion, each player must select one player that they want to eliminate when they vote.

...

Generally, the werewolves do not select their teammates, but other roles do select anyone when voting. Here comes the problem. How many werewolves at most under the given voting case.

Input

The first line of input file consists of an integer nn(2≤n≤5000002n500000), the number of players.

The second line of input file consists of nn integers, and the ii-th number xixi(1≤xi≤n,xi≠i1xin,xii) represents the number of the player selected by the i-th player.

Output

The output file should consist of only one integer, the maximum number of the existed werewolves.

Examples

Input 1

32 3 2

Output 1

2

题目大意:

    有一些好人和坏人(n<=500000),每个人会选择一个人,好人可以选择任意一个人,坏人只会选择好人。求最多有多少坏人。


解题思路:

    首先,第一眼看上去这一定是一个图论,也应该是一个dp。不过这题对于图的构成有着特殊的要求,往往这种时候这个特殊的要求就是解题的关键。仔细分析一下,如果我们把选择的关系反向作为一个有向边,那么这个图上的每个强连通分量一定都是一个环,然后在这个的一些节点上扩展了很多的树。

    假如没有这个环,那就是一个非常简单的树形dp,于是我们就可以枚举这个环上的一个点,然后我们就知道环上与这个点相邻的点的状态,这时环就退化成了一条链,整道题就成了一道非常简单的树形dp。


AC代码:

#include <iostream>#include <algorithm>#include <cstdio>#include <cstring>#include <vector>#include <queue>#include <cstdlib>#include <cmath>#include <string>#include <map>#include <stack>#include <ctime>#include <set>using namespace std;#define INF 0x3f3f3f3f#define LL long long#define fi first#define se second#define mem(a,b) memset((a),(b),sizeof(a))const int MAXN=500000+3;int N,dp[MAXN][2],fa[MAXN];vector<int> G[MAXN];//储存图bool vis[MAXN];//标记每个节点是否访问过void init()//初始化{    for(int i=1;i<=N;++i)    {        G[i].clear();        vis[i]=false;    }}int get_root(int u)//找到环上的一个点{    if(vis[u])        return u;    vis[u]=true;    return get_root(fa[u]);}void dfs0(int u,int father,int root)//根结点是好人时{    vis[u]=true;    dp[u][0]=0;    dp[u][1]=1;    for(int i=0;i<G[u].size();++i)    {        int v=G[u][i];        if(v==father||(u==fa[root]&&v==root))            continue;        dfs0(v,u,root);        dp[u][0]+=max(dp[v][1],dp[v][0]);        dp[u][1]+=dp[v][0];    }}void dfs1(int u,int father,int root)//根结点是坏人时{    vis[u]=true;    dp[u][0]=0;    dp[u][1]=1;    for(int i=0;i<G[u].size();++i)    {        int v=G[u][i];        if(v==father||(u==fa[root]&&v==root))            continue;        dfs1(v,u,root);        dp[u][0]+=max(dp[v][1],dp[v][0]);        dp[u][1]+=dp[v][0];    }    if(u==fa[root])        dp[u][1]=0;}int main(){    while(~scanf("%d",&N))    {        init();        for(int i=1;i<=N;++i)        {            scanf("%d",&fa[i]);            G[fa[i]].push_back(i);        }        int ans=0;        for(int i=1;i<=N;++i)            if(!vis[i])//一个新的连通分量            {                int root=get_root(i);//找到环上一个点,作为根结点                dfs0(root,-1,root);//假设根结点是好人                int the_max=dp[root][0];                dfs1(root,-1,root);//假设根结点是坏人                the_max=max(the_max,dp[root][1]);                ans+=the_max;            }        printf("%d\n",ans);    }        return 0;}

0 0