Zenefits CodeSprint:Knight or Knave
题意是一堆人,从1到n编号,每个人i说一句话,x。x是正数表示i说x君是个好人,x是负数表示i说x君是坏人。问这个群体中最多能有多少好人,把这种情况用字典序的方式输出(好人用A表示,坏人用B表示),希望我把题意说清楚了。
又做了一道Hackerrank上一道很好玩的题目,做的时候怎么都想不出来。。。
但看完了题解之后,又发现这个题目。。。
其实这个思路以前做并查集的时候有过,就是每个人就两种可能,即每个点就两种状态,那就对每个点再增加一个点,i增加一个点,i+n。这两个点始终都是对立的关系,如果i是好人,那么i+n一定是坏人。当时也想到dfs了,就是想把这个类的人归到一起去,比方说i是好人,i说j是好人,j说k是好人,那么就会希望i、j、k搞到一起去。这个时候就发挥了增加这个点的作用了,i比如是好人,i说j是坏人,那这个意思也就是i说j+n是坏人,i和j+n要搞到一起去,我靠,和并查集的一些题一样啊。。。。
后面就是查各个集的人数,胜利即是正义,人多即是正义。
官方题解代码:
#pragma warning(disable:4996)
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
using namespace std;
const int mx = 300003;
int n;
int norma(int x)
{
if (x < 0)
return abs(x) + n;
else
return x;
}
int inv(int x)
{
x = norma(x);
if (x > n)
return x - n;
else
return x + n;
}
vector<int>g[2 * mx];
int kc[mx];
int color[mx];
int flag[mx];
void call(int u, int mar)
{
if (color[u])
return;
color[u] = mar;
if (u <= n)
kc[mar]++;
for (int i = 0; i < g[u].size(); i++)
{
int v = g[u][i];
call(v, mar);
}
}
void addedge(int u, int v)
{
g[u].push_back(v);
}
int main()
{
//freopen("i.txt", "r", stdin);
//freopen("o.txt", "w", stdout);
int t, u, v, ass;
int invu, invt;
cin >> t;
while (t--)
{
memset(kc, 0, sizeof(kc));
memset(color, 0, sizeof(color));
cin >> n;
for (int i = 1; i <= 2 * n + 1; i++)
{
g[i].clear();
}
for (int i = 1; i <= n; i++)
{
u = i;
cin >> v;
v = norma(v);
addedge(u, v);
addedge(v, u);
invu = inv(u);
invt = inv(v);
addedge(inv(u), inv(v));
addedge(inv(v), inv(u));
}
ass = 0;
for (int i = 1; i <= n * 2; i++)
{
if (!color[i])
{
ass++;
call(i, ass);
}
}
memset(flag, 0, sizeof(flag));
for (int i = 1; i <= n; i++)
{
u = i;
v = inv(i);
u = color[u];
v = color[v];
if (!flag[u] && !flag[v])
{
if (kc[u] >= kc[v])//查数量,贪心,数量多的为好人
{
flag[u] = 1;
flag[v] = 2;
}
else
{
flag[u] = 2;
flag[v] = 1;
}
}
}
for (int i = 1; i <= n; i++)
{
if (flag[color[i]] == 1)
cout << "A";
else
cout << "B";
}
cout << endl;
}
//system("pause");
return 0;
}
浙公网安备 33010602011771号