2-SAT问题(宇航员分组,LA 3713)

来源:互联网 发布:linux命令解压缩 编辑:程序博客网 时间:2024/05/21 17:40

一共有三种任务,但是每个宇航员只能在其中某两种中选择一种。满足2-SAT模型的建模以及算法原理。(即每个人只能二选一)有向边uv表示选了u就要选v,这是一种限制而不是要求,所以我们依然可以把互相厌恨的条件满射成某些有向边。剩下的区别就只是搜索的时候加多一些讨论罢了。(比如dfs的失败条件不再是已经标记了另一个任务,而是另两个任务。)


防止精度问题可用乘法判断。


代码

#include<bits/stdc++.h>using namespace std;const int maxn = 100010;struct SAT3{    int n;    int N;    vector<int>G[maxn*3];    int mark[maxn*3];    int s[maxn*3],c;    int age[maxn];    int sum;    void add(int u,int v)    {        int U=u*3;        int V=v*3;        int bu=age[u]*n>=sum?1:0;        int bv=age[v]*n>=sum?1:0;        if(bu==bv)        {            G[U+(bu^1)].push_back(V+2);            G[V+2].push_back(U+(bu^1));            G[V+(bv^1)].push_back(U+2);            G[U+2].push_back(V+(bv^1));        }        else        {            G[V+2].push_back(U+(bu^1));            G[U+2].push_back(V+(bv^1));        }    }    void Read(int n,int m)    {        this->n=n;        N=n*3;        c=sum=0;        for(int i=0;i<N;i++)        {            G[i].clear();            mark[i]=0;        }        for(int i=0;i<n;i++)        {            scanf("%d",&age[i]);            sum+=age[i];        }        int u,v;        while(m--)        {            scanf("%d %d",&u,&v);            u--;v--;            add(u,v);        }    }    bool dfs(int u)    {        int temp=u%3;        if(mark[u-temp+(temp+1)%3]||mark[u-temp+(temp+2)%3]) return false;        if(mark[u]) return true;        mark[u]=true;        s[c++]=u;        for(unsigned int i=0;i<G[u].size();i++) if(!dfs(G[u][i])) return false;        return true;    }    bool solve()    {        for(int i=0;i<N;i+=3)        {            if(!mark[i]&&!mark[i+1]&&!mark[i+2])            {                c=0;                int bi=age[i/3]*n>=sum?1:0;                if(!dfs(i+(bi+1)%3))                {                    while(c>0) mark[s[--c]]=0;                    if(!dfs(i+(bi+2)%3)) return false;                }            }        }        return true;    }    void print()    {        //printf("%lf\n",1.0*sum/n);        for(int i=0;i<N;i+=3)            printf("%c\n",mark[i]?'A':mark[i+1]?'B':'C');    }};SAT3 S3;int main(){    int n,m;    while(scanf("%d %d",&n,&m)==2&&n&&m)    {        S3.Read(n,m);        if(S3.solve()) S3.print();        else puts("No solution.");    }    return 0;}


0 0
原创粉丝点击