[题解]TopCoder SRM 625 div2 T3 ConundrumReloaded

啊哈今日份TC

题目描述

有n个人围成一个圈,按照逆时针方向标号为0到n-1。这些人中有一些撒谎者。现在,你想知道最少有多少个人撒谎,于是你问了一些人他逆时针方向的人有没有撒谎。字符串answers描述了你所得到的答案:

  • answers[i]=’L’ 表示第i个人说第(i+1)个人撒谎了
  • answers[i]=’H’ 表示第i个人说第(i+1)个人没有撒谎
  • answers[i]=’?’ 表示你没有询问第i个人

如果至少能找到一种方案使得answers是合法的,输出最少的撒谎人数。否则输出-1

样例

Input1
LLH
Output1
1
根据输入:

  • 0说1撒谎了。
  • 1说2撒谎了。
  • 2说0没有撒谎。

显然,他们不可能都是诚实的,所以至少有一个人撒谎了。 可能1撒谎了而另外两个人没有。 因此,最少的撒谎人数就是一个。 (也有可能1没有撒谎,另外两人撒谎了,但是这种方案撒谎人数不是最小)

Input2
?????
Output2
0

Input3
LHLH?
Output3
2

Input4
??LLLLLL??
Output4
3

Input5
LLL
Output5
-1

根据输入:

  • 0说1撒谎了。
  • 1说2撒谎了。
  • 2说0撒谎了。

那么

  • 假设0撒谎了:1就没有撒谎,2撒谎了,那么根据2的回答,0没有撒谎,和假设矛盾
  • 假设0没撒谎:1撒谎了,2没有撒谎,那么根据2的回答,0撒谎了,和假设矛盾

所以没有合法的方案

分析

根据样例,我们可以发现,如果answers中没有’?’,我们可以通过0一个人的情况得出所有人有没有撒谎,最后通过n-1的回答判断这种方案是不是合法,最终得出答案。那么关键是处理’?’的情况。

假设answer[x]=’?’——

最先想到的就是暴力枚举两种情况——x+1撒谎了或者没有撒谎,但是如果字符串长度为50,每一个位上都是’?’,那么不剪枝大概是会T掉的,所以我们可以进行优化:

如果answers[x+1]也是’?’,那么x+1的情况就不会受限制,为了让答案尽量小,我们肯定默认x+1没有说谎,所以就不用判断说谎的情况了,这样大概就会优秀一点了

代码

既丑陋又充满废话的代码

//tc is healthy, just do it
#include <bits/stdc++.h>
const int N=55;
using namespace std;

template<class T> void checkmin(T &a,const T &b) { if (b<a) a=b; } 
template<class T> void checkmax(T &a,const T &b) { if (b>a) a=b; }

class ConundrumReloaded {
public:
    int minimumLiars( string answers ) ;
};

int n,a[N],b[N],ans,tot=0;
string answers;

void search(int pos,int lie,int num){//表示前pos个人的撒谎情况已知,第pos个
                                    //人是否撒谎,目前一共有num个人撒谎
    if(num>=ans)return;
    if(pos==n+1){
        if(lie==b[1]||lie==3){
            ans=min(ans,num);
        }
        return;
    }
    if(a[pos]!=3){
        if(lie==1){
            int yh=0;
            if(a[pos]==2&&pos!=n)yh=1;//注意要判断pos!=n,否则就会多算一个撒谎人数
            search(pos+1,3-a[pos],num+yh);
        }
        else{
            int yh=0;
            if(a[pos]==1&&pos!=n)yh=1;
            search(pos+1,a[pos],num+yh);
        }
    }
    else {
        if(a[pos+1]==3){
            search(pos+1,2,num);
            return;
        }
        search(pos+1,2,num);
        if(pos!=n)search(pos+1,1,num+1);    
        else search(pos+1,1,num);
    }
}

int ConundrumReloaded::minimumLiars(string answers) {
    n=answers.length();
    ans=n+1;
    for(int i=1;i<=n;i++){
        if(answers[i-1]=='L')a[i]=1;
        if(answers[i-1]=='H')a[i]=2;
        if(answers[i-1]=='?')a[i]=3;
    }
    b[1]=1;
    search(1,1,1);
    b[1]=2;
    search(1,2,0);
    if(ans==n+1)ans=-1;
    return ans;
}

猜你喜欢

转载自blog.csdn.net/Scl1231/article/details/82225888