タイトルにはA、B、Cの3つの状態がありますが、各個人は2つの状態しか選択できません。明らかに2-SATです。画像を作成するときに、i + nとしてA(またはB)を選択し、iとしてCを選択するとします。 ;最初に、2人が嫌いな場合、1人がCを選択し、もう1人は(x、y + n)と(y、x + n)の両サイドがあってももう一方を選択する必要があります。2人が同じタイプの場合、追加する必要があります。上限は、2人が同時にAを選択する(またはBを同時に選択する)ことを防止し、2つのサイド(x + n、y)、(y + n、x)を接続します。tarjan
が最後に回答を出力する場合、実行する必要はありません。一方はトポロジー的にソートされます。タージャンで強く接続されたコンポーネントが色付けされる順序はトポロジー的な順序であるため、col(i)<col(i + n)の場合はA(またはB)を選択し、それ以外の場合はCを選択することを意味します。
ピットに注意してください。2SAT問題で計画を出力する必要がある場合、コード出力がサンプルと異なっていても、2SAT問題には多くの解決策があるため、心配しないでください。その結果、私のサンプルは良くありません。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
typedef long long ll;
const int N = 5000007, M = 5000007, INF = 0x3f3f3f3f;
int n, m;
int dfn[N], low[N], num;
int head[N], ver[M], nex[M], tot;
int stk[N], top;
bool ins[M];
int scc_cnt;
int color[N];
void init()
{
memset(head, -1, sizeof head);
memset(dfn, 0, sizeof dfn);
memset(low, 0, sizeof low);
memset(color, 0, sizeof color);
tot = num = scc_cnt = 0;
}
int age[N];
void add(int x, int y)
{
ver[tot] = y;
nex[tot] = head[x];
head[x] = tot ++ ;
}
void tarjan(int x)
{
dfn[x] = low[x] = ++num;
stk[++ top] = x;
ins[x] = 1;
for(int i = head[x]; ~i; i = nex[i]){
int y = ver[i];
if(!dfn[y]){
tarjan(y);
low[x] = min(low[x], low[y]);
}
else if(ins[y])
low[x] = min(low[x], dfn[y]);
}
if(low[x] == dfn[x]){
int y;
++scc_cnt;
color[x] = scc_cnt;
do{
y = stk[top -- ];
ins[y] = false;
color[y] = scc_cnt;
}while(x != y);
}
}
int main()
{
while(scanf("%d%d", &n, &m)!= EOF && n + m){
init();
int sum = 0;
for(int i = 1;i <= n; ++ i){
scanf("%d", &age[i]);
sum += age[i];
}
for(int i = 1; i <= n; ++ i){
age[i] = (age[i] * n >= sum);
}
for(int i = 1; i <= m; ++ i){
int p, q;
scanf("%d%d", &p, &q);
//i + n : A / B
//i : B / C
if(age[p] == age[q])add(p + n, q), add(q + n, p);
add(p, q + n),add(q, p + n);
}
for(int i = 1; i <= 2 * n; ++i){
if(!dfn[i])
tarjan(i);
}
bool flag = 1;
for(int i = 1; i <= n; ++ i){
if(color[i] == color[i + n]){
puts("No solution."), flag = 0;
break;
}
}
if(!flag)continue;
for(int i = 1; i <= n; ++ i){
//谁小选谁 i + n 小的话,就是 i + n : A / B
if(color[i] > color[i + n]){
if(age[i])//根据题意1为大于平均值x,选A,B中的A
puts("A");
else puts("B");
}
else puts("C");
}
}
return 0;
}