# 題目: UVa 11659 - Informants
# 題目說明
題目給 n
個線人,並給 a
條規則,求最大可信賴的線人數
線人編號由 1 ~ n
若 1
可信賴,則 1
說的規則為真
若 1
不可信賴,則 1
說的規則可能為真或假
INPUT:
每筆測資先輸入兩個整數 n
、 a
, n
代表線人數、 a
代表規則數
接下來有 a
行,每行輸入兩個整數 x
、 y
- 若
y > 0
,代表線人x
信賴線人y
- 若
y < 0
,代表線人x
不信賴線人y
OUTPUT:
輸出最大可信賴的線人數
# 解題方法
使用 correct
與 wrong
分別儲存信賴與不信賴,儲存分法為 2進位
若線人 1
信賴線人 3
與 4
,則表示成 correct[1] = 1100
若線人 2
不信任線人 1
、 3
與 4
,則表示成 wrong[2] = 1101
遍歷所有可能的線人組合
若 n = 4
,則遍歷 0000
、 0001
、 ... 、 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/