LA 3713 宇航员分组

题目链接:http://vjudge.net/contest/142615#problem/B

题意:有A,B,C三个人物要分配个N个宇航员,每个宇航员恰好要分配一个任务,设平均年龄为X,只有年龄大于或等于X的宇航员才能分配任务A。只有年龄严格小于X的宇航员才能分配任务B。而任务C没有限制。有M对宇航员相互讨厌,因此不能分配到同一任务。编程找出一个满足上述所有要求的任务分配方案。

分析:

2-SAT。

建图:

肯定是不能同时去 C 的

 

同一类的话:

 

那么就是2a或者2b了,到底是哪个,就得看年龄了。

#include<cstdio>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
 
const int maxn = 100000 + 5;
 
struct TwoSAT
{
    int n;
    vector<int> G[maxn*2];
    bool mark[maxn*2];
    int S[maxn*2], c;
 
    bool dfs(int x)
    {
        if (mark[x^1]) return false;
        if (mark[x]) return true;
        mark[x] = true;
        S[c++] = x;
        for (int i = 0; i < G[x].size(); i++)
            if (!dfs(G[x][i])) return false;
        return true;
    }
 
    void init(int n)
    {
        this->n = n;
        for (int i = 0; i < n*2; i++) G[i].clear();
        memset(mark, 0, sizeof(mark));
    }
 
    // x = xval or y = yval
    void add_clause(int x, int xval, int y, int yval)
    {
        x = x * 2 + xval;
        y = y * 2 + yval;
        G[x^1].push_back(y);
        G[y^1].push_back(x);
    }
 
    bool solve()
    {
        for(int i = 0; i < n*2; i += 2)
            if(!mark[i] && !mark[i+1])
            {
                c = 0;
                if(!dfs(i))
                {
                    while(c > 0) mark[S[--c]] = false;
                    if(!dfs(i+1)) return false;
                }
            }
        return true;
    }
};
 
 
int n, m, total_age, age[maxn];
 
int is_young(int x)
{
    return age[x] * n < total_age;
}
 
TwoSAT solver;
 
int main()
{
    while(scanf("%d%d", &n, &m) == 2 && n && m)
    {
        total_age = 0;
        for(int i = 0; i < n; i++)
        {
            scanf("%d", &age[i]);
            total_age += age[i];
        }
 
        solver.init(n);
        for(int i = 0; i < m; i++)
        {
            int a, b;
            scanf("%d%d", &a, &b);
            a--;
            b--;
            if(a == b) continue;
            solver.add_clause(a, 1, b, 1); // 不能同去任务C
            if(is_young(a) == is_young(b)) // 同类宇航员
                solver.add_clause(a, 0, b, 0); // 不能同去任务A或者任务B
        }
 
        if(!solver.solve()) printf("No solution.
");
        else for(int i = 0; i < n; i++)
                if(solver.mark[i*2]) printf("C
"); // x[i]=false,去任务C
                else if(is_young(i)) printf("B
"); // x[i]=true的年轻宇航员去任务B
                else printf("A
"); // x[i]=true的年长宇航员去任务A
    }
    return 0;
}
原文地址:https://www.cnblogs.com/TreeDream/p/6103757.html