# 題目: UVa 11659 - Informants

# 題目說明

題目給 n 個線人,並給 a 條規則,求最大可信賴的線人數

線人編號由 1 ~ n
1 可信賴,則 1 說的規則為真
1 不可信賴,則 1 說的規則可能為真或假


INPUT:
每筆測資先輸入兩個整數 nan 代表線人數、 a 代表規則數
接下來有 a 行,每行輸入兩個整數 xy

  • y > 0 ,代表線人 x 信賴線人 y
  • y < 0 ,代表線人 x 不信賴線人 y

OUTPUT:
輸出最大可信賴的線人數

# 解題方法

使用 correctwrong 分別儲存信賴與不信賴,儲存分法為 2進位

若線人 1 信賴線人 34 ,則表示成 correct[1] = 1100
若線人 2 不信任線人 134 ,則表示成 wrong[2] = 1101

遍歷所有可能的線人組合

n = 4 ,則遍歷 00000001 、 ... 、 1111 所有可能

分別判斷各個線人是否存在這次的線人組合中

j 代表第 j 位線人, j 屬於 1 ~ n

若存在則進一步判斷規則是否有矛盾

線人 j 不信賴的線人是否存在於這次線人組合
線人 j 信賴的線人是否不存在於這次線人組合
若以上有至少一項為 ,則此線人組合矛盾

當此組合中的線人全部判斷完,且規則都沒有矛盾,則可計算這次可信賴的線人數

# 參考程式碼

#include <iostream>
#include <vector>
using namespace std;
static auto fast_io = []
{
	ios::sync_with_stdio(false);
	cout.tie(nullptr);
	cin.tie(nullptr);
	return 0;
}();
int main()
{
	int n, a, x, y;
	while (cin >> n >> a, n + a)
	{
		// init
		vector<int> correct(n + 1, 0);
		vector<int> wrong(n + 1, 0);
		int max_num = (1 << n);
		int ret = 0;
		// input
		for (int i = 0; i < a; ++i)
		{
			cin >> x >> y;
			if (y > 0) correct[x] |= (1 << (y - 1));  // if 1 trust 3 and 4, correct[1] = 1100
			else wrong[x] |= (1 << (-y - 1));
		}
		for (int i = 0; i < max_num; ++i) // all possible combination
		{
			bool feasible = true;
			for (int j = 1; j <= n; ++j) // each person 
			{
				int p = 1 << (j - 1);
				if ((i & p) == 0) continue; // j doesn't exist in i
				if ((i & wrong[j]) != 0 || (i & correct[j]) != correct[j]) // is there a contradiction
				{
					feasible = false;
					break;
				}
			}
			if (feasible)
			{
				int cnt = 0, cpy = i;
				while (cpy) cnt += cpy & 1, cpy >>= 1; // count the number of '1' in i (bitwise)
				ret = max(ret, cnt);
			}
		}
		cout << ret << "\n";
	}
}

# 參考資料

https://theriseofdavid.github.io/2021/04/23/UVa/UVa11659/