题目:
http://acm.hust.edu.cn/vjudge/contest/view.action?cid=72618#problem/F
题意:
有A,B,C三个任务要分给n个宇航员,年龄大于等于平均年龄的分A, 年龄小于平均年龄的分在B,C组没有界限,互为敌人的两个宇航员不可以在同一组.求出一个分配的方案.
思路:
2-SAT.
同一年龄互为敌人:
x^y=1 !x^!y=1
不同年龄互为敌人:
!x^!y=1
注意如果用平均数来对比的话有精度问题,要用age[i]*n>=sum. 或 age[i]*n <sum
AC.
#include <iostream>
#include <cstdio>
#include <vector>
#include <algorithm>
#include <cstring>
using namespace std;
const int MAXN = 2e5+5;
int age[100005];
int n, m, sum;
int V;
vector<int> G[200005];
vector<int> rG[200005];
vector<int> vs;
bool used[200005];
int cmp[200005];
void addedge(int from, int to)
{
G[from].push_back(to);
rG[to].push_back(from);
}
void dfs(int v)
{
used[v] = true;
for(int i = 0; i < G[v].size(); ++i) {
if(!used[G[v][i]]) dfs(G[v][i]);
}
vs.push_back(v);
}
void rdfs(int v, int k)
{
used[v] = 1;
cmp[v] = k;
for(int i = 0; i < rG[v].size(); ++i) {
if(!used[rG[v][i]]) rdfs(rG[v][i], k);
}
}
void scc()
{
memset(used, 0, sizeof(used));
vs.clear();
for(int v = 0; v < V; ++v) {
if(!used[v]) dfs(v);
}
memset(used, 0, sizeof(used));
int k = 0;
for(int i = vs.size()-1; i >= 0; --i) {
if(!used[vs[i]]) rdfs(vs[i], k++);
}
}
void build()
{
V = 2*n;
for(int i = 0; i < V; ++i) {
G[i].clear();
rG[i].clear();
}
for(int i = 0; i < m; ++i) {
int u, v;
scanf("%d %d", &u, &v);
u--; v--;
if((age[u]*n>=sum&&age[v]*n<sum) || (age[u]*n<sum&&age[v]*n>=sum)) {
addedge(n+u, v);
addedge(n+v, u);
}
else {
addedge(u, n+v);
addedge(v, n+u);
addedge(n+u, v);
addedge(n+v, u);
}
}
}
void solve()
{
build();
scc();
for(int i = 0; i < n; ++i) {
if(cmp[i] == cmp[n+i]) {
printf("No solution\n");
return;
}
}
for(int i = 0; i < n; ++i) {
if(cmp[i] > cmp[n+i]) {
if(age[i]*n >= sum) printf("A\n");
else printf("B\n");
}
else printf("C\n");
}
return;
}
int main()
{
//freopen("in", "r", stdin);
while(~scanf("%d %d", &n, &m)) {
if(n == 0 && m == 0) break;
sum = 0;
for(int i = 0; i < n; ++i) {
scanf("%d", &age[i]);
sum += age[i];
}
solve();
}
return 0;
}