ACM复习(57)17225 狼人游戏

Description

这里写图片描述

狼人游戏是一款深受大众欢迎的桌游。Ly作为初学者,自然也迷上这款刺激与智商并存的游戏。
可是有一件很忧伤的事,大家都知道狼人的角色牌分为狼人和非狼人,然后Ly经常玩一个晚上都抽不到狼人的角色。

为了抽到心爱的狼人,Ly开始观察主持人洗牌和发牌的规律。假设现在有n个人(分别编号1~n)玩游戏,也就是有n张牌,则主持人每一轮进行以下操作:
1.将手中的n张牌自顶到底编号1~n,并将它们从左到右放在反面放在桌面上;
2.记当前桌面剩下的牌里面,编号最小为m;
3.依此取编号为m,m+X,m+2*X….m+c*X的牌,直到m+c*X>n,每次取到的牌放到手牌的顶部;
4.如果桌面上还有牌,重复步骤2、3;否则洗牌完成,主持人重新将手牌自顶到底编号1~n;
5.游戏开始,主持人将第i张牌,发给编号为i的人;
6.游戏结束,主持人按游戏者编号回收角色牌,也就是第i个人的牌,放在第i位。

现在Ly知道自己的编号是k,还有就是在开局前,偷偷地把牌的初始状态记了下来,也就是说第一轮开始前第i张牌是不是狼人,Ly是知道的。游戏第一轮开始前主持人不洗牌。

由于大家今晚非常兴奋,打算玩通宵,你可以当作游戏进行了无数轮。Ly想知道他今晚有没有可能抽到狼人。但Ly正陶醉于游戏中,聪明的13级大神们,你可以帮Ly推测一下吗?O(∩_∩)O~

输入格式
第一行一个整数T(T<=20),表示测试数据的组数。
每组数据有两行。
第一行3个正整数n,X,k. n,X,k的含义如题目所述。
第二行一个长度为n的字符串,只由0和1组成。第i个字符代表初始状态下第i张牌的角色是不是狼人,1代表是,0代表不是。
数据范围:
3<=n<=1000
1<=k<=n
1<=X<=1000007

输出格式
每组数据输出一行。
如果Ly可以抽到狼人角色,输出”haha”;否则输出”hehe”。

输入样例
2
6 2 3
000010
6 2 1
000010

输出样例
haha
hehe

提示
1.在样例1中,第二轮开始前主持人洗牌后,角色牌的状况是000100;第三轮开始前主持人洗牌后的,角色牌的状况为010000;第四轮开始前主持人洗牌后,角色牌的状况为001000;于是坐在第3位
的Ly将在第四轮抽到狼人。
2.狼人角色牌的数量可以有多个。
3.此题用整体法和隔离法均可解,请认真思考分析。


解题思路

建立记录数组

record[ i ] = t
编号为 i 的牌下一轮游戏的编号为 t

则有:
t2 = record[ t ]
t3 = record[ t2 ]
t4 = record[ t3 ]

判断 tk == k || tk = i (即是否某一次游戏时编号等于k,或者回到初始编号)

#include<stdio.h>
int main()
{
    int t, n, x, k, total, index, flag, temp, temp2;
    int num[1002], record[1002], man[1002];
    char ch;
    scanf("%d", &t);

    while(t --)
    {
        scanf("%d %d %d", &n, &x, &k);
        total = n;
        flag = 0;

        scanf("%c", &ch);
        for(int i = 1; i <= n; i ++)
        {
            scanf("%c", &ch);
            man[i] = ch == '0' ? 0 : 1;
        }       

        for(int i = 1; i <= n; i ++)
            num[i] = i;

        // 按照游戏规则建立记录数组
        while(total >= 1)
        {   
            // 从剩下的牌中找到编号最小的
            for(index = 1; index <= n; index ++)
                if(num[index] != -1)
                    break;
            while(index <= n)
            {
                // 按照游戏规则:越早抽中的牌下次游戏时编号越大
                record[num[index]] = total;
                num[index] = -1;
                total --;
                index += x;
            }
        }

        for(int i = 1; i <= n; i ++)
        {
            // 如果编号为 i 的牌是狼人牌
            if(man[i] == 1)
            {
                temp = temp2 = i;
                while(record[temp] != k && record[temp] != temp2)
                    temp = record[temp];
                flag = record[temp] == k ? 1 : 0;
            }
            if(flag)
                break;
        }
        printf("%s\n", flag == 1 ? "haha" : "hehe"); 
    }
    return 0;
}
展开阅读全文

好像不难的算法题acm求解答

12-31
描述 去长春的飞机上,Bear Kids队跟One Piece队的队员深感无聊,于是,他们6个人玩起了一个很简单的游戏游戏规则是这样的,简化版狼人游戏游戏中,身份只有两种,平民跟狼人游戏分为天黑阶段跟天亮阶段,天黑的时候,狼人们会统一杀死一个平民,记住,是统一,随机,而已只有一个! 天亮的时候,所有人会出来投票杀死一个人,平民的话,会随机投一个人,当然,他不会投自己,狼人的话,他们会统一意见,集中投死一个平民,当然,也是随机。 得票最高的人就要被处死,如果有多人票数相同,则编号小的那个人被处死。 当游戏成员只剩平民时,平民胜利;当游戏成员只剩狼人时,狼人胜利。 那天,这六个人约好,输的一方请吃饭。六个人中,有两个狼人,四个平民,YYS跟WYH是狼人,LY,LYS,胖子,小马哥是平民,他们的游戏ID分别是1,2,3,4,5,6。 第一轮天黑的时候,YYS跟WYH就把LYS杀了,天亮的时候,YYS投了小马哥,WYH当然也投了小马哥,LY投了YYS,胖子投了LY,小马哥投了YYS(平民是随机投票的), 这时,由于YYS跟小马哥的票数相同,都是两票,但是,YYS是1号,小马哥是6号,因此,YYS挂了; 又一轮天黑,WYH把胖子杀了,天亮的时候,英明神武的LY跟小马哥都投了WYH(再强调一次,他们是随机投票的!),不用说了,WYH2票必须出局,平民胜利! 好了,未来的ACMER,现在你需要设计一个程序,要求是这样的:给出游戏人数,游戏轮数,接着再给出每一轮里面,天黑的时候谁死了,天亮的时候, 他们分别投票投了谁,最后是狼人胜利还是平民胜利。你根据这些条件,判断出有多少人可能是狼人。这题很简单,相信难不倒你! 输入格式 第一行输入一个数T(T<=100),表示CASE数,第二行,两个数n(2<=n<=1000),k(1<=k<n),分别表示游戏人数和游戏轮数, 注意,参与游戏的人员的编号是1到n,接着,有k行,每行第一个数x,表示天黑的时候,x被狼人杀死了,后面紧跟n个数, 分别代表n个人这一轮投票投了谁(编号),-1则表示该人已死,无投票权利,当然,最后一轮的时候,可能出现天黑狼人杀人后, 游戏直接结束了,那么,天亮的投票阶段则用n个0代替。最后一行,是字符串,“haha”表示狼人胜利,“hehe”表示平民胜利。 输出格式 每组数据输出一行,一个数res(res>0),表示有多少人可能是狼人。 输入样例 1 6 2 4 6 6 1 -1 3 1 5 -1 3 2 -1 -1 2 hehe 输出样例 2 我就暴力解 错了 我是先标记那些能够直接知道身份的 其他默认是狼人,然后进行判断,没有矛盾就是 就错了 #include <iostream> using namespace std; int a[1001][1001],c[1001],vote2[1001]; int vote[1001]; bool victory; string s; int last; int countn(int n,int k){ for(int i =1;i<=n;i++) if(c[i]==0){ int j=0; for(;j<k;j++){ if(a[j][i]==-1){j=k;break; } if(a[j][i]!=a[j][last]) break; } c[i]=j==k; } int num=0; for(int i =1;i<=n;i++) if(c[i]==1) {num++; } return num; } int deal(int n,int k) { for(int i=0; i<k; i++) c[a[i][0]]=-1; for(int i=1; i<=n; i++)if(a[k-1][i]!=-1) vote[a[k-1][i]]++; if(victory) { int maxn=0; for(int i=1; i<=n; i++) if(vote[i]>vote[maxn]) maxn=i; if(maxn!=0) { c[maxn]=-1; for(int i=1; i<=n; i++) { if(a[k-1][i]!=-1&&i!=maxn){ c[i]=1; last=i; } } } else { int maxn=0; for(int i=1; i<=n; i++)if(a[k-2][i]!=-1) vote2[a[k-2][i]]++; for(int i=1; i<=n; i++) if(vote2[i]>vote2[maxn]) maxn=i; for(int i=1; i<=n; i++) { if(a[k-2][i]!=-1&&i!=a[k-1][0]&&i!=maxn) {c[i]=1; last=i; } } } } else { int maxn=0; for(int i=1; i<=n; i++) if(vote[i]>vote[maxn]) maxn=i; c[maxn]=1; last=maxn; for(int i=1;i<=n;i++) if(a[k-1][i]!=-1&&i!=maxn) c[i]=-1; } return countn(n,k); } int main() { int t,n,k; cin>>t; while(t--) { cin>>n>>k; memset(c,0,sizeof(c)); memset(vote,0,sizeof(vote)); memset(vote2,0,sizeof(vote2)); for(int i=0; i<k; i++) for(int j=0; j<=n; j++) cin>>a[i][j]; cin>>s; victory=(s=="haha"); cout<< deal(n,k)<<endl; } return 0; }
©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值