UVa 1391 Astronauts (2SAT)

题意:给出一些宇航员他们的年龄,x是他们的平均年龄,其中A任务只能给年龄大于等于x的人,B任务只能给小于x的人,C任务没有限制。再给出m对人,他们不能同任务。现在要你输出一组符合要求的任务安排。

思路:2SAT。

设Ai表示第i个人的任务,如果i的年龄大于等于x,那么Ai=true表示分到A任务,flase表示分到C任务。如果i年龄小于x则Ai=true表示分到B任务,flase表示分到C任务。

考虑对于这m对里的每对人,如果他们是同组的,那么(Ai并非Aj)或(非Ai并Aj)等价于 (非Ai或非Aj)并(Ai或Aj)

如果他们是不同组的,那么只要他们都不是C任务就行,即非(非Ai并非Aj)等价于(Ai或Aj)

这样就可以用2SAT做了。注意平均年龄x要用浮点数。

我用的是LRJ的模板,2i表示Ai=false,2i+1表示Ai=true

#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
using namespace std;
const int maxn =100005;
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));
    }
    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;
    }
};
TwoSAT solver;
int age[100005];
int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(!n&&!m) break;
        double x=0;
        for(int i=0; i<n; ++i)
        {
            scanf("%d",&age[i]);
            x+=age[i];
        }
        x/=n;
        solver.init(n);
        for(int i=0; i<m; ++i)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            a--;
            b--;
            if((age[a]>=x&&age[b]>=x)||(age[a]<x&&age[b]<x))
            {
                solver.add_clause(a,0,b,0);
                solver.add_clause(a,1,b,1);
            }
            else
                solver.add_clause(a,1,b,1);
        }
        if(!solver.solve()) puts("No solution.");
        else
        {
            for(int i=0; i<2*n; i+=2)
                if(solver.mark[i])
                    printf("C\n");
                else
                    printf("%c\n",age[i/2]>=x?‘A‘:‘B‘);
        }
    }
    return 0;
}

UVa 1391 Astronauts (2SAT)

时间: 2024-12-19 14:44:37

UVa 1391 Astronauts (2SAT)的相关文章

uva 1391 Astronauts(2-SAT)

/*翻译好题意 n个变量 不超过m*2句话*/ #include<iostream> #include<cstdio> #include<cstring> #include<vector> #define maxn 200010 using namespace std; int n,m,f[maxn],c,s[maxn],age[maxn],sum,a,b; vector<int>G[maxn]; bool Judge(int a,int b)

UVA 1391 - Astronauts(2-SET)

UVA 1391 - Astronauts 题目链接 题意:给定一些宇航员,年龄小于平均数能做A和C,大于等于能做B和C,现在知道一些宇航员互相憎恨,不能让他们做同一个任务,问一直种安排方法满足条件 思路:2set问题,如果两种宇航员类型相同,就两个宇航员做不一样,加一条真或真,和假或假的边,如果类型不同,就加一条真或真的边 代码: #include <cstdio> #include <cstring> #include <cstdlib> #include <

UVAlive3713 Astronauts(2-SAT)

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18511 [思路] 2-SAT. 设分得A或B类任务为1 C类任务为0,考虑互相讨厌的两人:如果年龄阶段相同,则需要满足a!=b,即(a==1 or b==1)=1 && (a==0 or b==0)=1,如果年龄阶段不同,则需要满足ab不同时为C,即(a==1 or b==1)=1. [代码] 1 #include<cstdio> 2 #incl

UVA - 10534Wavio Sequence(LIS)

题目:UVA - 10534Wavio Sequence(LIS) 题目大意:给出N个数字,找出这样的序列:2 * n + 1个数字组成.前面的n + 1个数字单调递增,后面n + 1单调递减. 解题思路:从前往后找一遍LIS,再从后往前找一遍LIS.最后只要i这个位置的LIS的长度和LDS的长度取最小值.再*2 - 1就是这个波浪数字的长度.注意这里的求LIS要用nlog(n)的算法,而且这里的波浪数字的对称并不是要求i的LIS == LDS,而是只要求LIS和LDS最短的长度就行了,长的那个

POJ 3683 Priest John&#39;s Busiest Day(2-SAT)

[题目链接] http://poj.org/problem?id=3683 [题目大意] 每个婚礼有两个时段可以进行特别仪式,特别仪式必须要有神父在场, 神父只有一个,问是否能满足所有婚礼的需求, [题解] 因为两个时段必须要满足一个时段,所以如果一个时段被占用那么另一个时段必须被空出来, 我们根据各个婚礼两个时段之间的冲突关系建边,之后跑2-SAT,判断是否冲突, 若无冲突则输出方案. [代码] #include <cstdio> #include <algorithm> #in

uva 725 Division(除法)暴力法!

uva 725  Division(除法) A - 暴力求解 Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Description Write a program that finds and displays all pairs of 5-digit numbers that between them use the digits 0 through 9 once each, such that t

BZOJ 1997 Planar(2-SAT)

题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=1997 题意:给出一个无向图.已知该图存在一个包含n个顶点的哈密顿回路.判定该图是不是平面图. 思路:圈将面分成内外两部分,则两条边同时在内部相交则同时在外部也是相交的.因此,必然是一个在内部一个在外部.据此建立2-SAT.平面图的边数小于等于三倍点数减六 int a[N],b[N],n,m,c[N]; int d[N],f[N]; vector<int> g[2000]; void

Uva 11889 - Benefit( 数论 )

Uva 11889 - Benefit( 数论 ) 题意: calculate the lowest integer B such that LCM(A, B) = C 分析: LCM(A,B) = C = A*B/GCD(A,B)C*GCD(A,B) = A*BC/A = B/GCD(A,B)如果C%A != 0 无解否则, 令t = C/AB = t * GCD(A,B) 即B 一定是 t 的整数倍从t开始枚举B #include <cstdio> typedef long long LL

Go Deeper(2010成都现场赛题)(2-sat)

G - Go Deeper Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Description Here is a procedure's pseudocode: go(int dep, int n, int m) begin output the value of dep. if dep < m and x[a[dep]] + x[b[dep]] != c[dep] then go(dep +