SRM 572 Div 1 500 题解

Mark

这题难在细节上啊!不是TLE时间上啊!不要太关注一个题目的难点因为有可能判断错误T_T


原题描述

Problem Statement

 Elly and Kristina play a game called "Bulls". Initially each of them thinks of a non-negative integer with K digits, possibly containing leading zeroes. Then they take alternating turns, trying to guess the opponent's number. After each guess, the other person says how many positions were guessed correctly. For example if Kristina's number was "1337" and Elly's guess was "1738", Kristina should answer 2, since the digits at positions 0 and 2 (zero-based indices from the left) are correct. A guessed position is called "bull's hit", or simply a "bull", thus the name of the game.

Elly has already made several guesses. She wonders if the information she has is enough to uniquely determine Kristina's number.

You are given the guesses so far in a vector <string> guesses and the corresponding number of bull's hits in vector <int>bulls. If a unique number satisfies the given information, return it as a string. If there is more than one number that is valid according to the current guesses, return "Ambiguity" (quotes for clarity only). If no number satisfies the given information, then Kristina has lied and you should return "Liar" instead.

Definition

 
Class:EllysBulls
Method:getNumber
Parameters:vector <string>, vector <int>
Returns:string
Method signature:string getNumber(vector <string> guesses, vector <int> bulls)
(be sure your method is public)
 
 

Notes

-The game "Bulls" is a simplification of a game played in Bulgaria, called "Kravi & Bikove" ("Cows & Bulls").

Constraints

-guesses will contain between 1 and 50 elements, inclusive.
-Each element of guesses will contain between 2 and 9 characters, inclusive.
-All elements of guesses will contain the same number of characters.
-All elements of guesses will consist only of digits ('0'-'9').
-bulls will contain the same number of elements as guesses.
-Each element of bulls will be between 0 and K-1, inclusive, where K is the length of each element ofguesses.

Examples

0) 
 
{"1234", "4321", "1111", "2222", "3333", "4444", "5555", "6666", "7777", "8888", "9999"}
{2, 1, 1, 0, 2, 0, 0, 0, 1, 0, 0}
Returns: "1337"
From {1234->2, 2222->0, 4444->0} it follows that the number is {1?3?}. The additional information {4321->1} tells us that either the digit at position 1 (0-indexed) is 3, or that the one at position 3 is 1. However, since {1111->1} and we already know that the 0-th digit is 1, then the third digit cannot be 1. Now we know that the number is {133?}. When trying {7777->1} we see that Kristina's number contains a 7, which cannot be anywhere else except in the last position. Thus, her number is 1337.
1) 
 
{"0000", "1111", "2222"}
{2, 2, 2}
Returns: "Liar"
There are supposed to be two 0s, two 1s and two 2s in a four-digit number. Thus, Kristina is clearly a liar.
2) 
 
{"666666", "666677", "777777", "999999"}
{2, 3, 1, 0}
Returns: "Ambiguity"
Some of the possible configurations that satisfy the current results are the numbers 636172, 336617, 660007. Thus, the answer is ambiguous.
3) 
 
{"000", "987", "654", "321", "100", "010"}
{2, 1, 0, 0, 1, 1}
Returns: "007"
The guesses, as well as the answer, can have leading zeroes.
4) 
 
{"28", "92", "70", "30", "67", "63", "06", "65",
 "11", "06", "88", "48", "09", "65", "48", "08"}
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
Returns: "54"
5) 
 
{"0294884", "1711527", "2362216", "7666148", "7295642",
 "4166623", "1166638", "2767693", "8650248", "2486509",
 "6138934", "4018642", "6236742", "2961643", "8407361",
 "2097376", "6575410", "6071777", "3569948", "2606380"}
{1, 0, 1, 3, 4, 4, 3, 2, 1, 1, 0, 4, 4, 3, 0, 0, 0, 0, 2, 1}
Returns: "4266642"

This problem statement is the exclusive and proprietary property of TopCoder, Inc. Any unauthorized use or reproduction of this information without the prior written consent of TopCoder, Inc. is strictly prohibited. (c)2003, TopCoder, Inc. All rights reserved.


信任叙述

猜数字游戏玩儿过吧,假设答案是S。

给n<=50个长度相等最长为9的数字串(和S长度一样),对于每个字符串给出和S  数字和位置  都相同的位置个数。

求:

1、如果无解,输出Liar

2、如果多解,输出Ambiguity

3、如果单解,输出解。


算法

搜索。

本来想是每个位置直接搜索的,明显是1e9 * 50 要TLE啊sad。。

最多9位数字,于是就想到了 状态压缩 + 搜索,即枚举对于每个字符串有哪些位置是正确的。那么理论上复杂度最高是2 ^ 9 * 2 ^ 9 * 50

剪枝+优化

1、如果所有数字都枚举完全了,直接判断剩下的是否满足

2、如果一旦发现多解,输出多解

3、已经枚举过的位置不枚举

4、按照正确个数从大到小排序减小搜索树


细节

1、在无解和多解的判断上,dfs函数里面if (x >= n) 里是重点:

1)如果某一位没有枚举到:有可能是多解 | 后面某一位无解那么就是无解

2)如果某一位无解那么直接无解


函数的作用

init : 初始化幂数组mi,mm记录每个二进制数的1个数,ri记录含i个1个数的二进制数有哪些

check: 判断对于当前串和当前解有哪些位置重合,二进制压缩

makebad: 对于当前解和 当前串的枚举,造出新的bad数组(某一位的某个数不可以用)

ins : 枚举到当前串的时候在解中加入了一些数

reset : ins的逆过程

isbad : 枚举的时候碰到了不可以用的位置和数

puliccheck : 对于已经枚举完的情况判断之后是否正确

dfs : 枚举过程 (位置 x , 已经得到的位置压缩 all , 不可以用的位置和数 bad)


代码

typedef long long LL;
//typedef long double DB;
typedef double DB;
typedef unsigned UINT;
typedef unsigned long long ULL;

typedef vector<int> VI;
typedef vector<char> VC;
typedef vector<string> VS;
typedef vector<LL> VL;
typedef vector<DB> VF;
typedef set<int> SI;
typedef set<string> SS;
typedef map<int, int> MII;
typedef map<string, int> MSI;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef vector<PII> VII;
typedef vector<VI> VVI;
typedef vector<VII> VVII;

template<class T> inline void RST(T &A){memset(A, 0, sizeof(A));}
template<class T> inline void FLC(T &A, int x){memset(A, x, sizeof(A));}

template<class T> inline void checkMin(T &a, T b){if (b<a) a=b;}
template<class T> inline void checkMax(T &a, T b){if (b>a) a=b;}

/* -&$&#*( &#*@)^$@&*)*/

const int MOD = 1000000007;
const int INF = 0x7fffffff;

const int N = 50;
typedef vector<int> VI;

class EllysBulls {
public:
    vector <string > g ;
    VI r;
    int len , n;
    int ans[100] , out[100];

    int mm[1 << 10] , mi[10];
    VI ri[10];
    void init(){
        REP(i , len) {ri[i].clear() , mi[i] = 1 << i;}
        REP_C(i , (1 << len)){
            mm[i] = 0;
            int j = i;
            while(j){
                mm[i] += j & 1;
                j >>= 1;
            }
            ri[mm[i]].PB(i);
        }
    }
    int check(int x){
        int res = 0;
        REP(i , len){
            if (ans[i] != -1 && g[x][i] == '0' + ans[i])
                res |= mi[i];
        }
        return res;
    }
    void makebad(int x , int now , bool newbad[10][10] , bool bad[10][10]){
        REP_2(i , j , len , 10) newbad[i][j] = bad[i][j];
        REP(i , len)
        if (!(now & mi[i]))
            newbad[i][g[x][i] - '0'] = 1;
        else{
            REP(j , 10)
                newbad[i][j] = (j == g[x][i] - '0');
        }
    }
    void ins(int x , int now){
        REP(i , len) if (now & mi[i])
            ans[i] = g[x][i] - '0';
    }
    void reset(int x , int now){
        REP(i , len) if (now & mi[i])
            ans[i] = -1;
    }
    bool isbad(int x , int now , bool bad[10][10]){
        REP(i , len) if (now & mi[i])
            if (bad[i][g[x][i] - '0']) return true;
        return false;
    }
    int publiccheck(int st){
        for( ; st < n ; ++st){
            int res = 0;
            REP(i , len)
                res += ans[i] == g[st][i] - '0';
            if (res != r[st]) return 0;
        }
        return 1;
    }
    int dfs(int x , int all , bool bad[10][10]){
        if(all == mi[len] - 1) return publiccheck(x + 1);
        if (x >= n){
                    int ret = 1;
                    REP(i , len){
                        if (ans[i] != -1 || (all & mi[i])) continue;
                        int res = -1;
                        REP(j , 10){
                            if (!bad[i][j]){
                                if (res != -1) ret = 2;
                                res = j;
                            }
                        }
                        if (res == -1) return 0;

                        ans[i] = res;
                    }

                    REP(i , len) out[i] = ans[i];
                    if (ret > 1) return 2;
                    return 1;
        }
        int now = check(x);
        if (mm[now] > r[x]) return 0;
        bool newbad[10][10];
        int ret = 0;
        REP_C(i , SZ(ri[r[x] - mm[now]])){
            int add = ri[r[x] - mm[now]][i];
            if (add & all) continue;
            if (isbad(x , add , bad)) continue;
            makebad(x , (add | now) , newbad , bad);
            ins(x , add);
            ret += dfs(x + 1 , (all | add) , newbad);
            reset(x , add);
            if (ret > 1) {
                    return ret;
            }
        }
        return ret;
    }
	string getNumber(vector <string> guesses, vector <int> bulls) {
		g = guesses;
        r = bulls;
		len = g[0].length();
		n = SZ(g);
		REP_2(i , j , n , i){
		    if(r[j] < r[i]){
                swap(r[i] , r[j]);
                swap(g[i] , g[j]);
		    }
		}
		FLC(ans , -1);
		init();
		bool bad[10][10];
		RST(bad);
		int res = dfs(0 , 0 , bad);
        if (res == 0) return "Liar";
        if (res > 1) return "Ambiguity";
        string ret = "";
        REP(i , len){
            ret += (out[i] + '0');
        }
        return ret;
	}
};

数据

	int run_test_case(int casenum) {
		switch (casenum) {
		case 0: {
			string guesses[]          = {"1234", "4321", "1111", "2222", "3333", "4444", "5555", "6666", "7777", "8888", "9999"};
			int bulls[]               = {2, 1, 1, 0, 2, 0, 0, 0, 1, 0, 0};
			string expected__         = "1337";

			clock_t start__           = clock();
			string received__         = EllysBulls().getNumber(vector <string>(guesses, guesses + (sizeof guesses / sizeof guesses[0])), vector <int>(bulls, bulls + (sizeof bulls / sizeof bulls[0])));
			return verify_case(casenum, expected__, received__, clock()-start__);
		}

		case 1: {
			string guesses[]          = {"0000", "1111", "2222"};
			int bulls[]               = {2, 2, 2};
			string expected__         = "Liar";

			clock_t start__           = clock();
			string received__         = EllysBulls().getNumber(vector <string>(guesses, guesses + (sizeof guesses / sizeof guesses[0])), vector <int>(bulls, bulls + (sizeof bulls / sizeof bulls[0])));
			return verify_case(casenum, expected__, received__, clock()-start__);
		}

		case 2: {
			string guesses[]          = {"666666", "666677", "777777", "999999"};
			int bulls[]               = {2, 3, 1, 0};
			string expected__         = "Ambiguity";

			clock_t start__           = clock();
			string received__         = EllysBulls().getNumber(vector <string>(guesses, guesses + (sizeof guesses / sizeof guesses[0])), vector <int>(bulls, bulls + (sizeof bulls / sizeof bulls[0])));
			return verify_case(casenum, expected__, received__, clock()-start__);
		}
		case 3: {
			string guesses[]          = {"000", "987", "654", "321", "100", "010"};
			int bulls[]               = {2, 1, 0, 0, 1, 1};
			string expected__         = "007";

			clock_t start__           = clock();
			string received__         = EllysBulls().getNumber(vector <string>(guesses, guesses + (sizeof guesses / sizeof guesses[0])), vector <int>(bulls, bulls + (sizeof bulls / sizeof bulls[0])));
			return verify_case(casenum, expected__, received__, clock()-start__);
		}
		case 4: {
			string guesses[]          = {"28", "92", "70", "30", "67", "63", "06", "65",
 "11", "06", "88", "48", "09", "65", "48", "08"};
			int bulls[]               = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
			string expected__         = "54";

			clock_t start__           = clock();
			string received__         = EllysBulls().getNumber(vector <string>(guesses, guesses + (sizeof guesses / sizeof guesses[0])), vector <int>(bulls, bulls + (sizeof bulls / sizeof bulls[0])));
			return verify_case(casenum, expected__, received__, clock()-start__);
		}
		case 5: {
			string guesses[]          = {"0294884", "1711527", "2362216", "7666148", "7295642",
 "4166623", "1166638", "2767693", "8650248", "2486509",
 "6138934", "4018642", "6236742", "2961643", "8407361",
 "2097376", "6575410", "6071777", "3569948", "2606380"};
			int bulls[]               = {1, 0, 1, 3, 4, 4, 3, 2, 1, 1, 0, 4, 4, 3, 0, 0, 0, 0, 2, 1};
			string expected__         = "4266642";

			clock_t start__           = clock();
			string received__         = EllysBulls().getNumber(vector <string>(guesses, guesses + (sizeof guesses / sizeof guesses[0])), vector <int>(bulls, bulls + (sizeof bulls / sizeof bulls[0])));
			return verify_case(casenum, expected__, received__, clock()-start__);
		}

		// custom cases

      case 6: {
			string guesses[]          = {"689717881","729469886","836709781","182159888","389571851","802979001","855698811","883017381","287479881","689187881","186272081","549279841","829259582","889209851","465277831","489034841","854257830","583859981","451171881","829977181","589259281","584819788","189275655","389989186","888219281","389364881","289619892","488379911","739371471","399229321","589077481","889372855","074279488","489276833","879734481","849279825","715279981","386309883","899779505","115174081","687279667","987289061","789279812","082577871","419709881","178279821","587503881","815432882","809271664","886556286"};
			int bulls[]               = {5,4,4,4,5,4,3,4,6,5,5,6,5,7,4,4,3,4,4,5,6,3,4,4,6,5,4,4,3,4,5,5,4,5,4,6,5,4,4,3,4,4,6,4,5,5,4,3,4,3};
			string expected__         = "ABC";

			clock_t start__           = clock();
			string received__         = EllysBulls().getNumber(vector <string>(guesses, guesses + (sizeof guesses / sizeof guesses[0])), vector <int>(bulls, bulls + (sizeof bulls / sizeof bulls[0])));
			return verify_case(casenum, expected__, received__, clock()-start__);
		}
      case 7: {
			string guesses[]          = {"000000000", "111111111", "222222222", "333333333", "444444444", "555555555", "666666666", "777777777", "888888888", "999999999", "000000000", "111111111", "222222222", "333333333", "444444444", "555555555", "666666666", "777777777", "888888888", "999999999", "000000000", "111111111", "222222222", "333333333", "444444444", "555555555", "666666666", "777777777", "888888888", "999999999", "000000000", "111111111", "222222222", "333333333", "444444444", "555555555", "666666666", "777777777", "888888888", "999999999", "000000000", "111111111", "222222222", "333333333", "444444444", "555555555", "666666666", "777777777", "888888888", "999999999"};
			int bulls[]               = {1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,1,0,1,1,1,1,1,1,1,1,2,0};
			string expected__         = "Liar";

			clock_t start__           = clock();
			string received__         = EllysBulls().getNumber(vector <string>(guesses, guesses + (sizeof guesses / sizeof guesses[0])), vector <int>(bulls, bulls + (sizeof bulls / sizeof bulls[0])));
			return verify_case(casenum, expected__, received__, clock()-start__);
		}
      case 8: {
			string guesses[]          = {"00000000", "10000001", "07000008", "02000020", "00600070", "00300300", "00050600", "00044000", "80005000"};
			int bulls[]               = {0, 1, 1, 1, 1, 1, 1, 1, 1};
			string expected__         = "Ambiguity";

			clock_t start__           = clock();
			string received__         = EllysBulls().getNumber(vector <string>(guesses, guesses + (sizeof guesses / sizeof guesses[0])), vector <int>(bulls, bulls + (sizeof bulls / sizeof bulls[0])));
			return verify_case(casenum, expected__, received__, clock()-start__);
		}
		default:
			return -1;
		}
	}
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值