杭电多校第六次 HDU6370 Werewolf(记忆化搜索)

Werewolf
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1443 Accepted Submission(s): 395

Problem Description
“The Werewolves” is a popular card game among young people.In the basic game, there are 2 different groups: the werewolves and the villagers.

Each player will debate a player they think is a werewolf or not.

Their words are like “Player x is a werewolf.” or “Player x is a villager.”.

What we know is :

  1. Villager won’t lie.

  2. Werewolf may lie.

Of cause we only consider those situations which obey the two rules above.

It is guaranteed that input data exist at least one situation which obey the two rules above.

Now we can judge every player into 3 types :

  1. A player which can only be villager among all situations,

  2. A player which can only be werewolf among all situations.

  3. A player which can be villager among some situations, while can be werewolf in others situations.

You just need to print out the number of type-1 players and the number of type-2 players.

No player will talk about himself.

Input
The first line of the input gives the number of test cases T.Then T test cases follow.

The first line of each test case contains an integer N,indicating the number of players.

Then follows N lines,i-th line contains an integer x and a string S,indicating the i-th players tell you,”Player x is a S.”

limits:

1≤T≤10

1≤N≤100,000

1≤x≤N

S∈ {“villager”.”werewolf”}

Output
For each test case,print the number of type-1 players and the number of type-2 players in one line, separated by white space.

Sample Input
1
2
2 werewolf
1 werewolf

Sample Output
0 0

大佬卡题,题卡我
这道题有思路,但却硬生生的WA了好多次。。
emmmmm…
解析:
全部是狼人满足所有情况
所以确定为村民的个数为0
所以可以想到通过dfs判断一定是狼的个数,
我们以村民为边建图,如果有狼回到了村民,那么就把前半部分设置为狼,后面则可以是村民
为了防止超时,还要记忆化一下,记忆化的过程代码中有注释

#include<bits/stdc++.h>
using namespace  std;
#define ll long long
#define pb push_back
#define inf 0x3f3f3f3f
#define mod 1000000007
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define pre(i,a,b) for(int i=a;i>=b;i--)
const int N=1e5+10;
int vis[N];
int ri[N];
int du[N];
int sum3=0,pp=-1,flag=1;
void dfs(int now)
{
    vis[now]=-2;
    if(ri[now]>0)
    {
        int a=ri[now];
        if(vis[a]==0)//没有搜索过,继续搜
            dfs(a);
        else if(vis[a]==-1) pp=now;//搜索到了狼
        else pp=vis[a];//搜索到了村民,就要找
        //村民最末端的狼,如果狼在这个环内,那么显然pp
        //之前的都是狼,否则都可以是村民
    }
    else
    {
        int a=-ri[now];//出现狼的边,直接记录一下就好
            pp=a;
    }
    if(now==pp) flag=0;
    if(!flag) vis[now]=-1;
    else vis[now]=pp;
}
int main()
{
    #ifdef local
        freopen("D://rush.txt","r",stdin);
    #endif
    ios::sync_with_stdio(false);
    int t;
    cin>>t;
    string s;
    while(t--)
    {
        memset(vis,0,sizeof vis);
        memset(ri,0,sizeof ri);
        sum3 =0;
        int n,a;
        cin>>n;
        for(int i=1;i<=n;i++)
        {
            cin>>a>>s;
            if(s[0]=='v')
                ri[i]=a;
            else
                ri[i]=-a;
        }
        for(int i=1;i<=n;i++)
        {
            if(vis[i]==0)
            {
                pp=-1,flag=1;
                dfs(i);
            }
        }
        rep(i,1,n)
            if(vis[i]==-1) sum3++;
        printf("0 %d\n",sum3);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值