1. 程式人生 > >[題解]TopCoder SRM 625 div2 T3 ConundrumReloaded

[題解]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;
}