1148 Werewolf - Simple Version (20 分)

Werewolf(狼人杀) is a game in which the players are partitioned into two parties: the werewolves and the human beings. Suppose that in a game,

  • player #1 said: "Player #2 is a werewolf.";
  • player #2 said: "Player #3 is a human.";
  • player #3 said: "Player #4 is a werewolf.";
  • player #4 said: "Player #5 is a human."; and
  • player #5 said: "Player #4 is a human.".

Given that there were 2 werewolves among them, at least one but not all the werewolves were lying, and there were exactly 2 liars. Can you point out the werewolves?

Now you are asked to solve a harder version of this problem: given that there were N players, with 2 werewolves among them, at least one but not all the werewolves were lying, and there were exactly 2 liars. You are supposed to point out the werewolves.

Input Specification:

Each input file contains one test case. For each case, the first line gives a positive integer N (5≤N≤100). Then N lines follow and the i-th line gives the statement of the i-th player (1≤i≤N), which is represented by the index of the player with a positive sign for a human and a negative sign for a werewolf.

Output Specification:

If a solution exists, print in a line in ascending order the indices of the two werewolves. The numbers must be separated by exactly one space with no extra spaces at the beginning or the end of the line. If there are more than one solution, you must output the smallest solution sequence -- that is, for two sequences A=a[1],...,a[M] and B=b[1],...,b[M], if there exists 0≤k<M such that a[i]=b[i] (i≤k) and a[k+1]<b[k+1], then A is said to be smaller than B. In case there is no solution, simply print No Solution.

Sample Input 1:

5
-2
+3
-4
+5
+4

Sample Output 1:

1 4

Sample Input 2:

6
+6
+3
+1
-5
-2
+4

Sample Output 2 (the solution is not unique):

1 5

Sample Input 3:

5
-2
-3
-4
-5
-1

Sample Output 3:

No Solution

 

心路历程:首先,暴风哭泣!开始看到这个题,想着作为一个20分的题稍微有点复杂,但是无论如何还是觉得自己能在最多1个小时以内写完的!没想到修修改改写了3个小时!主要原因是一开始按lier的顺序排列,结果看清题意后一切重来555

解题思路:

1.字符串转整数 substr;然后存在数组a里,a[i]正数则代表i说abs(a[i])是好人,负数代表i说abs(a[i])是狼

2.多个结果要求输出字典最小序列,则我们可以从前往后标狼,这样一定是最小序答案

If there are more than one solution, you must output the smallest solution sequence -- that is, for two sequences A=a[1],...,a[M] and B=b[1],...,b[M], if there exists 0≤k<M such that a[i]=b[i] (i≤k) and a[k+1]<b[k+1], then A is said to be smaller than B. In case there is no solution, simply print No Solution.

(不得不吐槽题目这英文解释像shit)

3.标定lier,注意有且仅有一只狼是lier

4.判断每个人所述是否矛盾,不矛盾则找到第一组解即答案

PS.由于楼主一开始理解题意有误,可能尚写的有点复杂和不完善(已过PAT测试);大家自行改进吧!

 

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

const int N = 105;
int a[N];
int wolf[N];//1狼 -1好人
bool lier[N];
int n;
int wolfA,wolfB;
int wa,wb;

bool fun()
{
    memset(wolf,0,sizeof(wolf));
    wolf[wa] = wolf[wb] = 1;//标狼
    for(int i = 1; i <= n; i++){
        int t = abs(a[i]);
        if(lier[i]){//i说谎
//            printf("%d说谎,t=%d\n",i,a[i]);
            if(a[i]>0){//t是狼
                if(t!=wa&&t!=wb) return false;
            }
            else {//t是好人
                if(wolf[t]==1) return false;
                wolf[t] = -1;
            }
        }
        else {
//            printf("%d未说谎,t=%d\n",i,a[i]);
            if(a[i]>0){//t是好人
                if(wolf[t]==1) return false;
                wolf[t] = -1;
            }
            else {//t是狼
                if(t!=wa&&t!=wb) return false;
            }
        }
//        for(int i = 1; i <= n; i++){
//            cout << wolf[i] << " ";
//        }
//        cout << endl;
    }
    return true;
}


bool judge()//判断假设是否成立
{
    memset(lier,false,sizeof(lier));
    lier[wa] = true;//有且仅有一只狼说谎
    for(int i = 1; i <= n; i++){
        if(i!=wa&&i!=wb){
            lier[i] = true;
            if(fun()) return true;
            lier[i] = false;
        }
    }
    memset(lier,false,sizeof(lier));
    lier[wb] = true;
    for(int i = 1; i <= n; i++){
        if(i!=wa&&i!=wb){
            lier[i] = true;
            if(fun()) return true;
            lier[i] = false;
        }
    }
    return false;

}

bool solve()
{
    memset(wolf,0,sizeof(wolf));
    for(int i = 1; i <= n; i++){
        for(int j = i+1; j <= n; j++){//保证最小顺序
//            printf("%d和%d是狼:\n",i,j);
            wa = i,wb= j;
            if(judge()){//找到满足方案,返回
                wolfA = i;
                wolfB = j;
                return true;
            }
        }
    }
    return false;//未找到满足方案
}

int change(string s)
{
    return atoi(s.c_str());
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++){
        string s;
        cin >> s;
        if(s[0]=='+'){
            a[i] = change(s.substr(1,s.size()-1));
        }
        else if(s[0]=='-'){
            a[i] = -1*change(s.substr(1,s.size()-1));
        }
    }
    if(solve()){
        cout <<wolfA<<" "<<wolfB;
    }
    else cout << "No Solution";
    return 0;
}

 

贴一下错误答案(不做参考,仅做教训):粗心到题目是说输出按狼的字典序,而我写成lier的字典序,血淋淋的教训:做了一下午!

#include <iostream>
#include <bits/stdc++.h>
using namespace std;

const int N = 105;
int a[N];
bool lier[N];
int wolf[N];//0未确定;1狼;-1不是狼;
int n;

bool judge()//判断假设是否成立
{
    memset(wolf,0,sizeof(wolf));
    for(int i = 1; i <= n; i++){
        if(!lier[i]){//i未说谎
            //printf("%d未说谎,t=%d\n",i,a[i]);
            int t = abs(a[i]);
            if(a[i] > 0){//t是好人
                if(wolf[t]==1) return false;//矛盾
                wolf[t] = -1;
            }
            else {//t是狼
                if(wolf[t]==-1) return false;//矛盾
                wolf[t] = 1;
            }
        }
        else {//i说谎
            //printf("%d说谎,t=%d\n",i,a[i]);
            int t = abs(a[i]);
            if(a[i] > 0){//t是狼
                if(wolf[t]==-1) return false;
                wolf[t] = 1;
            }
            else {//t是好人
                if(wolf[t]==1) return false;
                wolf[t] = -1;
            }
        }
        /*
        for(int i = 1; i <= n; i++){
            cout << wolf[i] << " ";
        }
        cout << endl;
        */
    }
    int cnt_0 = 0;//没有做出指证的数,即wolf值为0的数
    int wolfs = 0;//狼的个数
    int lier_wolf = 0;//说谎的狼的个数,注意题目说明有且仅有一只狼说谎
    int lier_0 = 0;//wolf值为0且说谎的个数
    for(int i = 1; i <= n; i++){
        if(wolf[i]==0) cnt_0++;
        if(wolf[i]==1) wolfs++;
        if(wolf[i]==1&&lier[i]) lier_wolf++;
        if(lier[i]&&wolf[i]==0) lier_0++;
    }
    if(wolfs!=2&&cnt_0+wolfs!=2) return false;
    if(lier_wolf>1) return false;
    if(lier_wolf+lier_0!=1) return false;//说谎的狼只有一头
    return true;
}

bool solve()
{
    memset(lier,false,sizeof(lier));
    for(int i = 1; i <= n; i++){
        for(int j = i+1; j <= n; j++){
            lier[i] = lier[j] = true;
            if(judge()) return true;//找到满足方案,返回
            lier[i] = lier[j] = false;//记得清楚上一轮的假设
        }
    }
    return false;//未找到满足方案
}

int change(string s)
{
    return atoi(s.c_str());
}

int main()
{
    cin >> n;
    for(int i = 1; i <= n; i++){
        string s;
        cin >> s;
        if(s[0]=='+'){
            a[i] = change(s.substr(1,s.size()-1));
        }
        else if(s[0]=='-'){
            a[i] = -1*change(s.substr(1,s.size()-1));
        }
    }
    if(solve()){
        int flag = 0;
        for(int i = 1; i <= n; i++){
            if(wolf[i]==1){
                cout << i;
                if(flag!=1) cout << " ";//注意输出格式
                else break;
                flag++;
            }
        }
    }
    else cout << "No Solution";
    return 0;
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值