思路:一开始考虑n个朋友可以有c种可能,根据回答的问题,如果是yes那么可以确定一些朋友的范围,将原本不在这个范围内的删除即可;如果是“no”,说明这些朋友都应该被删除,那么最后看第i个人候选的情况是不是只有一种,如果是直接输出名字,否则就是不确定或者不存在。下面介绍利用贡献优化,并且非常好写的方法。
AC代码
#include <cstdio> #include <cmath> #include <cctype> #include <algorithm> #include <cstring> #include <utility> #include <string> #include <iostream> #include <map> #include <set> #include <vector> #include <queue> #include <stack> using namespace std; #pragma comment(linker, "/STACK:1024000000,1024000000") #define eps 1e-10 #define inf 0x3f3f3f3f #define PI pair<int, int> typedef long long LL; const int maxn = 200 + 5; string name[maxn]; int vis[maxn][maxn]; int a[maxn][maxn]; map<string, int>ha; int getId(string p) { return ha[p]; } int main() { int T, n, q, c; scanf("%d", &T); while(T--) { ha.clear(); scanf("%d%d", &n, &q); scanf("%d", &c); for(int i = 0; i < c; ++i) { cin >> name[i]; ha[name[i]] = i; } vector<int>que[maxn]; memset(vis, 0, sizeof(vis)); for(int i = 0; i < q; ++i) { int m; scanf("%d", &m); string s; for(int j = 0; j < m; ++j) { cin >> s; que[i].push_back(getId(s)); } } for(int i = 0; i < n; ++i) { for(int j = 0; j < c; ++j) vis[i][j] = 1; for(int j = 0; j < q; ++j) { scanf("%d", &a[i][j]); if(a[i][j]) { for(int k = 0; k < c; ++k) if(vis[i][k]) { int f = 0; for(int h = 0; h < que[j].size(); ++h) { if(que[j][h] == k) { f = 1; break; } } if(!f) vis[i][k] = 0; } } else { for(int k = 0; k < que[j].size(); ++k) { vis[i][que[j][k]] = 0; } } } } for(int i = 0; i < n; ++i) { int cnt = 0; int ind; for(int j = 0; j < c; ++j) { if(vis[i][j]) { ++cnt; ind = j; } } if(cnt == 1) { cout << name[ind] << endl; } else printf("Let's go to the library!!\n"); } } return 0; }
更好的思路:每一个人被每一个问题赋予了一定的贡献,第i个问题的贡献是2^i(二进制)。
例如:
4 Serval Raccoon Alpaca Moose
1 Serval
1 Fennec
1 Serval
第一个问题对Serval Raccoon Alpaca Moose四人的贡献为2^0,
第二个问题对Serval贡献为2^1,下面的问题同理;“”
最后根据对问题的回答情况,确定第i(0 < i < n)人的贡献,查找人名中是否有唯一与之对应的,如果有输出人名,否则输出“Let's go to the library!!”,时间复杂度为O(n*c)。这种方法非常巧妙,降低了复杂度。
AC代码
#include <cstdio> #include <cmath> #include <cctype> #include <algorithm> #include <cstring> #include <utility> #include <string> #include <iostream> #include <map> #include <set> #include <vector> #include <queue> #include <stack> using namespace std; #pragma comment(linker, "/STACK:1024000000,1024000000") #define eps 1e-10 #define inf 0x3f3f3f3f #define PI pair<int, int> typedef long long LL; const int maxn = 200 + 5; string name[maxn]; map<string, int>ha; int w[30], g[maxn]; void init() { w[0] = 1; for(int i = 1; i <= 25; ++i) w[i] = w[i-1] * 2; } int main() { init(); int T, n, q, c; scanf("%d", &T); while(T--) { ha.clear(); scanf("%d%d", &n, &q); scanf("%d", &c); for(int i = 0; i < c; ++i) { cin >> name[i]; ha[name[i]] = i; g[i] = 0; } for(int i = 0; i < q; ++i) { string s; int m; scanf("%d", &m); while(m--) { cin >> s; g[ha[s]] += w[i]; } } for(int i = 0; i < n; ++i) { int sum = 0; for(int j = 0; j < q; ++j) { int f; scanf("%d", &f); if(f) sum += w[j]; } int cnt = 0, peo; for(int j = 0; j < c; ++j) { if(g[j] == sum) { ++cnt; peo = j; } } if(cnt == 1) cout << name[peo] << endl; else printf("Let's go to the library!!\n"); } } return 0; }
由于测试数据不够强,导致二种方法时间相差不大:强烈建议掌握第二种的思路。
如有不当之处欢迎指出!