码迷,mamicode.com
首页 > 其他好文 > 详细

2-SAT 学习笔记

时间:2016-08-16 23:35:29      阅读:212      评论:0      收藏:0      [点我收藏+]

标签:

总结了下就三句话:

1.确定集合,以及每个集合必须二选一的状态

2.枚举相关的集合,再枚举相关集合可能出现的会影响状态选择的矛盾情况

3.以矛盾为前提,确定的情况才加边

 

1.POJ 3227

每条连线当作是一个集合,每个集合的状态是在圆内或者圆外,任意两个集合都可能出现矛盾,矛盾是位置交叉

技术分享
#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"map"
#include"set"
#include"vector"
#include"bitset"
#define LL long long
#define ull unsigned long long
#define mems(a,b) memset(a,b,sizeof(a))
#define mdzz int mid=(L+R)>>1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int N = 2e5+50;
const int M = 1e5+5;
const LL MOD = 1e9+7;
const int INF = 0x3f3f3f3f;

int block,tp,tot,id;
int low[N],dfn[N],ins[N];
int st[N],belong[N];
int first[N];

struct node{
    int e,next;
    node(){}
    node(int a,int b):e(a),next(b){}
}edge[N];;

void init(){
    tot=0;id=0;tp=0;
    mems(first,-1);
    mems(dfn,0);
    mems(ins,0);
}

void addedge(int u,int v){
    edge[tot]=node(v,first[u]);
    first[u]=tot++;
}

void tarjan(int u){
    low[u]=dfn[u]=++id;
    ins[u]=1;
    st[++tp]=u;
    for(int i=first[u];i!=-1;i=edge[i].next){
        int v=edge[i].e;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(ins[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        block++;
        int v;
        do{
            v=st[tp--];
            ins[v]=0;
            belong[v]=block;
            //sz[block]++;
        }
        while(v!=u);
    }
}

int n,m;
int u[N],v[N];

bool check(int i,int j){
    if(u[i]>u[j]&&u[i]<v[j]&&v[i]>v[j]) return true;
    return false;
}

int main(){
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m)){
        init();
        for(int i=0;i<m;i++){
            scanf("%d%d",&u[i],&v[i]);
            u[i]++;v[i]++;
            if(u[i]>v[i]) swap(u[i],v[i]);
        }
        for(int i=0;i<m;i++)
        for(int j=i+1;j<m;j++) if(check(i,j)||check(j,i)){

            addedge(i<<1,j<<1|1);
            addedge(j<<1,i<<1|1);
            addedge(i<<1|1,j<<1);
            addedge(j<<1|1,i<<1);
        }
        for(int i=0;i<2*m;i++) if(!dfn[i]) tarjan(i);
        int f=1;
        for(int i=0;i<2*m;i++) if(belong[i]==belong[i^1]){
            f=0;
            break;
        }
        if(f) printf("panda is telling the truth...\n");
        else printf("the evil panda is lying again\n");
    }
    return 0;
}
View Code

2.POJ 3683 

每个婚礼时间当作一个集合,每个集合的两个状态是在开头或者结尾举办仪式,任意两个集合都可能出现矛盾,矛盾是时间交叉

技术分享
#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"map"
#include"set"
#include"vector"
#include"bitset"
#define LL long long
#define ull unsigned long long
#define mems(a,b) memset(a,b,sizeof(a))
#define mdzz int mid=(L+R)>>1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int N = 4e3+50;
const int M = 1e6+5;
const LL MOD = 1e9+7;
const int INF = 0x3f3f3f3f;

int block,tp,tot,id;
int low[N],dfn[N],ins[N];
int st[N],belong[N];
int first[N],deg[N];

struct node{
    int s,e,next;
    node(){}
    node(int a,int b,int c):s(a),e(b),next(c){}
}edge[M<<2];

void init(){
    tot=0;id=0;tp=0;
    mems(first,-1);
    mems(dfn,0);
    mems(ins,0);
    mems(deg,0);
}

void addedge(int u,int v){
    //cout<<u<<‘ ‘<<v<<endl;
    edge[tot]=node(u,v,first[u]);
    first[u]=tot++;
}

void tarjan(int u){
    low[u]=dfn[u]=++id;
    ins[u]=1;
    st[++tp]=u;
    for(int i=first[u];i!=-1;i=edge[i].next){
        int v=edge[i].e;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(ins[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        block++;
        int v;
        do{
            v=st[tp--];
            ins[v]=0;
            belong[v]=block;
            //sz[block]++;
        }
        while(v!=u);
    }
}

int n,m;
int t[N];
struct Node{
    int h,m;
    int id(){
        return h*60+m;
    }
    void display(){
        if(h<10) printf("0");
        printf("%d:",h);
        if(m<10) printf("0");
        printf("%d",m);
    }
}s[N],e[N],tmp;

bool check(Node i,Node j,Node k,Node p){
    if(j.id()<=k.id()||p.id()<=i.id()) return false;
    return true;
}

Node _get(Node a,int x){
    a.m+=x;
    while(a.m<0) a.h--,a.m+=60;
    while(a.h<0) a.h+=24;
    a.h+=a.m/60;
    a.m%=60;
    return a;
}

//vector<int> Ant[N],topo;
int Ant[N];
queue<int> q;

void rebuild(){
    for(int i=0;i<2*n;i++) Ant[belong[i]]=belong[i^1];
        //Ant[belong[i]].push_back(belong[i^1]);
    int tot2=tot;
    mems(first,-1);
    tot=0;
    for(int i=0;i<tot2;i++){
        if(belong[edge[i].s]==belong[edge[i].e]) continue;
        deg[belong[edge[i].s]]++;
        addedge(belong[edge[i].e],belong[edge[i].s]);
    }
}

int col[N];
void toposort(){
    mems(col,0);
    //topo.clear();
    while(!q.empty()) q.pop();
    for(int i=1;i<=block;i++) if(!deg[i]) q.push(i);
    while(!q.empty()){
        int u=q.front();q.pop();
        //topo.push_back(u);
        if(!col[u]){
            col[u]=1;
            col[Ant[u]]=-1;
        }
        for(int i=first[u];i!=-1;i=edge[i].next){
            int v=edge[i].e;
            deg[v]--;
            if(!deg[v]) q.push(v);
        }
    }
}

int main(){
    //freopen("in.txt","r",stdin);
    while(~scanf("%d",&n)){
        init();
        for(int i=0;i<n;i++) scanf("%d:%d %d:%d %d",&s[i].h,&s[i].m,&e[i].h,&e[i].m,&t[i]);

        for(int i=0;i<n;i++)
        for(int j=i+1;j<n;j++){
            if(check(s[i],_get(s[i],t[i]),s[j],_get(s[j],t[j]))){
                addedge(i<<1,j<<1|1);
                addedge(j<<1,i<<1|1);
            }
            if(check(s[i],_get(s[i],t[i]),_get(e[j],-t[j]),e[j])){
                addedge(i<<1,j<<1);
                addedge(j<<1|1,i<<1|1);
            }
            if(check(_get(e[i],-t[i]),e[i],s[j],_get(s[j],t[j]))){
                addedge(i<<1|1,j<<1|1);
                addedge(j<<1,i<<1);
            }
            if(check(_get(e[i],-t[i]),e[i],_get(e[j],-t[j]),e[j])){
                addedge(i<<1|1,j<<1);
                addedge(j<<1|1,i<<1);
            }
        }
        for(int i=0;i<2*n;i++) if(!dfn[i]) tarjan(i);
        int f=1;
        for(int i=0;i<2*n;i+=2) if(belong[i]==belong[i+1]){
            f=0;
            break;
        }
        //for(int i=0;i<2*n;i++) cout<<i<<‘ ‘<<belong[i]<<endl;
        if(!f){
            printf("NO\n");
            continue;
        }
        else printf("YES\n");
        rebuild();
        toposort();
        for(int i=0;i<n;i++){
            if(col[belong[i<<1]]==1){
                s[i].display();printf(" ");
                tmp=_get(s[i],t[i]);
                tmp.display();printf("\n");
            }
            else{
                tmp=_get(e[i],-t[i]);
                tmp.display();printf(" ");
                e[i].display();printf("\n");
            }
        }
    }
    return 0;
}
View Code

3.POJ 3678

每个点当作一个集合,每个集合的两个状态是0或者1,有边相连的两个集合才可能出现矛盾,矛盾的情况是不符合运算规则

技术分享
#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"map"
#include"set"
#include"vector"
#include"bitset"
#define LL long long
#define ull unsigned long long
#define mems(a,b) memset(a,b,sizeof(a))
#define mdzz int mid=(L+R)>>1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int N = 4e3+50;
const int M = 4e6+5;
const LL MOD = 1e9+7;
const int INF = 0x3f3f3f3f;

int block,tp,tot,id;
int low[N],dfn[N],ins[N];
int st[N],belong[N];
int first[N],deg[N];

struct node{
    int s,e,next;
    node(){}
    node(int a,int b,int c):s(a),e(b),next(c){}
}edge[M];

void init(){
    tot=0;id=0;tp=0;
    block=0;
    mems(first,-1);
    mems(dfn,0);
    mems(ins,0);
    mems(deg,0);
}

void addedge(int u,int v){
    edge[tot]=node(u,v,first[u]);
    first[u]=tot++;
}

void tarjan(int u){
    low[u]=dfn[u]=++id;
    ins[u]=1;
    st[++tp]=u;
    for(int i=first[u];i!=-1;i=edge[i].next){
        int v=edge[i].e;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(ins[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        block++;
        int v;
        do{
            v=st[tp--];
            ins[v]=0;
            belong[v]=block;
            //sz[block]++;
        }
        while(v!=u);
    }
}
int n,m;
char op[5];
int main(){
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m)){
        init();
        int u,v,w,x,f=1;
        for(int i=0;i<m;i++){
            scanf("%d%d%d%s",&u,&v,&x,op);
            if(op[0]==O){
                if(x){
                    addedge(u<<1,v<<1|1);
                    addedge(v<<1,u<<1|1);
                }
                else{
                    addedge(u<<1|1,u<<1);
                    addedge(v<<1|1,v<<1);
                }
            }
            else if(op[0]==X){
                if(x){
                    addedge(u<<1,v<<1|1);
                    addedge(v<<1,u<<1|1);
                    addedge(u<<1|1,v<<1);
                    addedge(v<<1|1,u<<1);
                }
                else{
                    addedge(u<<1,v<<1);
                    addedge(v<<1,u<<1);
                    addedge(u<<1|1,v<1|1);
                    addedge(v<<1|1,u<<1|1);
                }
            }
            else if(op[0]==A){
                if(x){
                    addedge(u<<1,u<<1|1);
                    addedge(v<<1,v<<1|1);
                }
                else{
                    addedge(v<<1|1,u<<1);
                    addedge(u<<1|1,v<<1);
                }
            }
        }
        for(int i=0;i<n*2;i++) if(!dfn[i]) tarjan(i);
        for(int i=0;i<2*n;i+=2) if(belong[i]==belong[i+1]){
            f=0;
            break;
        }
        if(f) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}
View Code

4.POJ 2723

捆绑的两把钥匙当作一个集合,每个集合的两个状态是使用其中的某一把,矛盾的情况是一个门的两把锁只需要开一把

技术分享
#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"map"
#include"set"
#include"vector"
#include"bitset"
#define LL long long
#define ull unsigned long long
#define mems(a,b) memset(a,b,sizeof(a))
#define mdzz int mid=(L+R)>>1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int N = 1e4+50;
const int M = 1e5+5;
const LL MOD = 1e9+7;
const int INF = 0x3f3f3f3f;

int block,tp,tot,id;
int low[N],dfn[N],ins[N];
int st[N],belong[N];
int first[N];
int n,m;

struct node{
    int s,e,next;
    node(){}
    node(int a,int b,int c):s(a),e(b),next(c){}
}edge[M];

void init(){
    tot=0;id=0;tp=0;
    block=0;
    mems(first,-1);
    mems(dfn,0);
    mems(ins,0);
}

void addedge(int u,int v){
    //cout<<u<<‘ ‘<<v<<endl;
    edge[tot]=node(u,v,first[u]);
    first[u]=tot++;
}

void tarjan(int u){
    low[u]=dfn[u]=++id;
    ins[u]=1;
    st[++tp]=u;
    for(int i=first[u];i!=-1;i=edge[i].next){
        int v=edge[i].e;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(ins[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        block++;
        int v;
        do{
            v=st[tp--];
            ins[v]=0;
            belong[v]=block;
            //sz[block]++;
        }
        while(v!=u);
    }
}

int mat[N],loc[N<<1][2];
int u,v;

bool check(int mid){
    init();
    for(int i=0;i<mid;i++){
        addedge(loc[i][0],mat[loc[i][1]]);
        addedge(loc[i][1],mat[loc[i][0]]);
    }
    for(int i=0;i<2*n;i++) if(!dfn[i]) tarjan(i);
    for(int i=0;i<2*n;i++) if(belong[i]==belong[mat[i]]) return false;
    return true;
}

int main(){
    //freopen("in.txt","r",stdin);
    while(scanf("%d%d",&n,&m)&&(n||m)){
        //init();
        for(int i=0;i<n;i++){
            scanf("%d%d",&u,&v);
            mat[u]=v;mat[v]=u;
        }
        for(int i=0;i<m;i++) scanf("%d%d",&loc[i][0],&loc[i][1]);
        int ans=0;
        int low=0,high=m,mid;
        //check(mid);
        while(low<=high){
            mid=(low+high)>>1;
            if(check(mid)){
                ans=mid;
                low=mid+1;
            }
            else high=mid-1;
            //cout<<mid<<endl;
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

5.POJ 2749

每头牛的两种选择当作一个集合,每个集合的状态是选择其中的某一个中转,矛盾的情况是题目中给的以及对于每两个点的四种连接情况中距离大于枚举的maxdis的时候

技术分享
#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"map"
#include"set"
#include"vector"
#include"bitset"
#define LL long long
#define ull unsigned long long
#define mems(a,b) memset(a,b,sizeof(a))
#define mdzz int mid=(L+R)>>1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int N = 1e3+50;
const int M = 1e6+100000;
const LL MOD = 1e9+7;
const int INF = 0x3f3f3f3f;

int block,tp,tot,id;
int low[N],dfn[N],ins[N];
int st[N],belong[N];
int first[N];
int n,m;

struct node{
    int s,e,next;
    node(){}
    node(int a,int b,int c):s(a),e(b),next(c){}
}edge[M];

void init(){
    tot=0;id=0;tp=0;
    block=0;
    mems(first,-1);
    mems(dfn,0);
    mems(ins,0);
}

void addedge(int u,int v){
    edge[tot]=node(u,v,first[u]);
    first[u]=tot++;
}

void tarjan(int u){
    low[u]=dfn[u]=++id;
    ins[u]=1;
    st[++tp]=u;
    for(int i=first[u];i!=-1;i=edge[i].next){
        int v=edge[i].e;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(ins[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        block++;
        int v;
        do{
            v=st[tp--];
            ins[v]=0;
            belong[v]=block;
            //sz[block]++;
        }
        while(v!=u);
    }
}

struct Point{
    int x,y;
}p[N],s,e;

int dis(Point a,Point b){
    return abs(a.x-b.x)+abs(a.y-b.y);
}

int u,v,A,B;
int a[N][2],b[N][2];

bool check(int mid){
    init();
    for(int i=0;i<A;i++){
        addedge(a[i][0]<<1,a[i][1]<<1|1);
        addedge(a[i][0]<<1|1,a[i][1]<<1);
        addedge(a[i][1]<<1,a[i][0]<<1|1);
        addedge(a[i][1]<<1|1,a[i][0]<<1);
    }
    for(int i=0;i<B;i++){
        addedge(b[i][0]<<1,b[i][1]<<1);
        addedge(b[i][0]<<1|1,b[i][1]<<1|1);
        addedge(b[i][1]<<1,b[i][0]<<1);
        addedge(b[i][1]<<1|1,b[i][0]<<1|1);
    }
    for(int i=0;i<n;i++)
    for(int j=i+1;j<n;j++){
        if(dis(s,p[i])+dis(s,p[j])>mid){
            addedge(i<<1,j<<1|1);
            addedge(j<<1,i<<1|1);
        }
        if(dis(e,p[i])+dis(e,p[j])>mid){
            addedge(i<<1|1,j<<1);
            addedge(j<<1|1,i<<1);
        }
        if(dis(s,p[i])+dis(e,p[j])+dis(s,e)>mid){
            addedge(i<<1,j<<1);
            addedge(j<<1|1,i<<1|1);
        }
        if(dis(e,p[i])+dis(s,p[j])+dis(s,e)>mid){
            addedge(i<<1|1,j<<1|1);
            addedge(j<<1,i<<1);
        }
    }
    for(int i=0;i<2*n;i++) if(!dfn[i]) tarjan(i);
    for(int i=0;i<2*n;i+=2) if(belong[i]==belong[i+1]) return false;
    return true;
}

int main(){
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d%d",&n,&A,&B)){
        //init();
        scanf("%d%d%d%d",&s.x,&s.y,&e.x,&e.y);
        for(int i=0;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y);
        for(int i=0;i<A;i++) scanf("%d%d",&a[i][0],&a[i][1]),a[i][0]--,a[i][1]--;
        for(int i=0;i<B;i++) scanf("%d%d",&b[i][0],&b[i][1]),b[i][0]--,b[i][1]--;

        int low=0,high=INF,mid,ans=-1;
        while(low<=high){
            mid=(high-low)/2+low;
            if(check(mid)){
                ans=mid;
                high=mid-1;
            }
            else low=mid+1;
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

6.POJ 2296

每个点的两种选择当作一个集合,每个集合的状态是在上方或者在下方,矛盾的情况是矩形是否相交

技术分享
#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"map"
#include"set"
#include"vector"
#include"bitset"
#define LL long long
#define ull unsigned long long
#define mems(a,b) memset(a,b,sizeof(a))
#define mdzz int mid=(L+R)>>1
#define ls pos<<1
#define rs pos<<1|1
#define lson L,mid,pos<<1
#define rson mid+1,R,pos<<1|1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int N = 2e3+5;
const int M = 1e5+5;
const LL MOD = 1e9+7;
const int INF = 0x3f3f3f3f;

struct node{
    int x,y;
}p[N];

bool cmp(node a,node b){
    if(a.x==b.x) return a.y<b.y;
    return a.x<b.x;
}

int block,tp,tot,id;
int low[N],dfn[N],ins[N];
int st[N],belong[N];
int first[N];

struct Node{
    int e,next;
    Node(){}
    Node(int a,int b):e(a),next(b){}
}edge[M];

void addedge(int u,int v){
    //cout<<u<<‘ ‘<<v<<endl;
    edge[tot]=Node(v,first[u]);
    first[u]=tot++;
}

void init(){
    tot=0;id=0;tp=0;
    block=0;
    mems(first,-1);
    mems(dfn,0);
    mems(ins,0);
}

void tarjan(int u){
    low[u]=dfn[u]=++id;
    ins[u]=1;
    st[++tp]=u;
    for(int i=first[u];i!=-1;i=edge[i].next){
        int v=edge[i].e;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(ins[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        block++;
        int v;
        do{
            v=st[tp--];
            ins[v]=0;
            belong[v]=block;
            //sz[block]++;
        }
        while(v!=u);
    }
}

int T,n;
bool check(int mid){
    init();
    for(int i=0;i<n;i++)
    for(int j=i+1;j<n;j++){
        if(abs(p[j].y-p[i].y)>=2*mid||abs(p[j].x-p[i].x)>=mid) continue;

        if(p[i].y<p[j].y){
            if(p[j].y-p[i].y>=mid){
                addedge(i+n,j+n);
                addedge(j,i);
            }
            else{
                addedge(i,j+n);
                addedge(j+n,i);
                addedge(i+n,i);
                addedge(j,j+n);
            }
        }
        else if(p[i].y>p[j].y){
            if(p[i].y-p[j].y>=mid){
                addedge(j+n,i+n);
                addedge(i,j);
            }
            else{
                addedge(i+n,j);
                addedge(j,i+n);
                addedge(i,i+n);
                addedge(j+n,j);
            }
        }
        else {
            addedge(i,j+n);
            addedge(i+n,j);
            addedge(j+n,i);
            addedge(j,i+n);
        }
    }
    for(int i=0;i<2*n;i++) if(!dfn[i]) tarjan(i);
    for(int i=0;i<2*n;i+=2) if(belong[i]==belong[i+1]) return false;
    return true;
}

int main(){
    //freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=0;i<n;i++) scanf("%d%d",&p[i].x,&p[i].y);
        sort(p,p+n,cmp);
        int low=0,high=INF,mid,ans=0;
        while(low<=high){
            mid=(low+high)>>1;
            if(check(mid)){
                ans=mid;
                low=mid+1;
            }
            else high=mid-1;
        }
        //check(2);
        printf("%d\n",ans);
    }
    return 0;
}
View Code

7. HDU 3622

每个炸弹的两种位置当作一个集合,矛盾的情况是两个炸弹影响范围相交(不知道为什么写成+n模式的就会挂,写异或模式就行。。难道是因为长得丑?

技术分享
#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"map"
#include"set"
#include"vector"
#include"bitset"
#define LL long long
#define ull unsigned long long
#define mems(a,b) memset(a,b,sizeof(a))
#define mdzz int mid=(L+R)>>1
#define ls pos<<1
#define rs pos<<1|1
#define lson L,mid,pos<<1
#define rson mid+1,R,pos<<1|1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int N = 505;
const int M = 8e4+5;
const LL MOD = 1e9+7;
const int INF = 0x3f3f3f3f;

int block,tp,tot,id;
int low[N],dfn[N],ins[N];
int st[N],belong[N];
int first[N];

struct node{
    int e,next;
    node(){}
    node(int a,int b):e(a),next(b){}
}edge[M];

struct Node{
    double x,y;
    void read(){
        scanf("%lf%lf",&x,&y);
    }
}p[N];

void init(){
    tot=0;id=0;tp=0;
    block=0;
    mems(dfn,0);
    mems(ins,0);
    mems(first,-1);
    mems(low,0);
}

void addedge(int u,int v){
    edge[tot]=node(v,first[u]);
    first[u]=tot++;
}

void tarjan(int u){
    low[u]=dfn[u]=++id;
    ins[u]=1;
    st[++tp]=u;
    for(int i=first[u];i!=-1;i=edge[i].next){
        int v=edge[i].e;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(ins[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        block++;
        int v;
        do{
            v=st[tp--];
            ins[v]=0;
            belong[v]=block;
            //sz[block]++;
        }
        while(v!=u);
    }
}

int n;

double dis(Node a,Node b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

bool check(double mid){
    init();
    for(int i=0;i<n*2;i++)
    for(int j=i+1;j<n*2;j++){
        if(dis(p[i],p[j])<mid){
            addedge(i,j^1);
            addedge(j,i^1);
        }
    }
    for(int i=0;i<n*2;i++) if(!dfn[i]) tarjan(i);
    for(int i=0;i<n*2;i+=2) if(belong[i]==belong[i+1]) return false;
    return true;
}

int main(){
    //freopen("in.txt","r",stdin);
    while(~scanf("%d",&n)){
        for(int i=0;i<n;i++) //p[i].read(),p[i+n].read();
            scanf("%lf%lf%lf%lf",&p[i*2].x,&p[i*2].y,&p[i*2+1].x,&p[i*2+1].y);
        double low=0,high=1e5,mid,ans=0;
        while(high-low>1e-4){
            mid=(low+high)/2.0;
            if(check(mid)){
                ans=mid;
                low=mid;
            }
            else high=mid;
        }

        printf("%.2f\n",ans/2);
    }
    return 0;
}
View Code

8. HDU 1814

论文题,但是要输出最小字典序答案,只能暴力O(n*m)

技术分享
#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"map"
#include"set"
#include"vector"
#include"bitset"
#define LL long long
#define ull unsigned long long
#define mems(a,b) memset(a,b,sizeof(a))
#define mdzz int mid=(L+R)>>1
#define ls pos<<1
#define rs pos<<1|1
#define lson L,mid,pos<<1
#define rson mid+1,R,pos<<1|1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int N = 2e4+5;
const int M = 5e4+5;
const LL MOD = 1e9+7;
const int INF = 0x3f3f3f3f;

int block,tp,tot,id;
int low[N],dfn[N],ins[N];
int st[N],belong[N];
int first[N],col[N];
int n,m,u,v;

struct node{
    int s,e,next;
    node(){}
    node(int a,int b,int c):s(a),e(b),next(c){}
}edge[M];

void init(){
    tot=0;
    mems(first,-1);
    mems(col,-1);
}

void addedge(int u,int v){
    //cout<<u<<‘ ‘<<v<<endl;
    edge[tot]=node(u,v,first[u]);
    first[u]=tot++;
}

///1 选 0 不选
int ans[N],cnt;

bool dfs(int u){
    if(col[u]==1) return true;
    if(col[u]==0) return false;
    col[u]=1;col[u^1]=0;ans[cnt++]=u;
    for(int i=first[u];i!=-1;i=edge[i].next){
        int v=edge[i].e;
        if(!dfs(v)){
            //col[u]=col[u^1]=-1;
            return false;
        }
    }
    return true;
}

void solve(){
    for(int i=0;i<2*n;i++) if(col[i]==-1){
        cnt=0;
        if(!dfs(i)){
            for(int j=0;j<cnt;j++) col[ans[j]]=col[ans[j]^1]=-1;
            cnt=0;
            if(!dfs(i^1)){
                printf("NIE\n");
                return;
            }
        }
    }
    for(int i=0;i<2*n;i++) if(col[i]==1) printf("%d\n",i+1);
}

int main(){
    //freopen("in.txt","r",stdin);
    while(~scanf("%d%d",&n,&m)){
        init();
        for(int i=0;i<m;i++){
            scanf("%d%d",&u,&v);
            u--;v--;
            addedge(u,v^1);
            addedge(v,u^1);
        }
        solve();
    }
    return 0;
}
View Code

9.HDU 4115

由于是要求不能输,所以每局只能赢或平两种状态

令A表示赢的出法,A‘表示平局的出法

若要求两局出法相同,枚举两局的四种出法,比如若A!=B,显然两局不能都赢,则加边A->B‘,其他三种情况类似

要求不同出法的情况与上面类似

技术分享
#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"map"
#include"set"
#include"vector"
#include"bitset"
#define LL long long
#define ull unsigned long long
#define mems(a,b) memset(a,b,sizeof(a))
#define mdzz int mid=(L+R)>>1
#define ls pos<<1
#define rs pos<<1|1
#define lson L,mid,pos<<1
#define rson mid+1,R,pos<<1|1
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;

const int N = 2e4+5;
const int M = 2e5+5;
const LL MOD = 1e9+7;
const int INF = 0x3f3f3f3f;

int block,tp,tot,id;
int low[N],dfn[N],ins[N];
int st[N],belong[N];
int first[N];

struct node{
    int e,next;
    node(){}
    node(int a,int b):e(a),next(b){}
}edge[M];

void init(){
    tot=0;id=0;tp=0;
    block=0;
    mems(first,-1);
    mems(dfn,0);
    mems(ins,0);
}

void addedge(int u,int v){
    edge[tot]=node(v,first[u]);
    first[u]=tot++;
}

void tarjan(int u){
    low[u]=dfn[u]=++id;
    ins[u]=1;
    st[++tp]=u;
    for(int i=first[u];i!=-1;i=edge[i].next){
        int v=edge[i].e;
        if(!dfn[v]){
            tarjan(v);
            low[u]=min(low[u],low[v]);
        }
        else if(ins[v]) low[u]=min(low[u],dfn[v]);
    }
    if(low[u]==dfn[u]){
        block++;
        int v;
        do{
            v=st[tp--];
            ins[v]=0;
            belong[v]=block;
            //sz[block]++;
        }
        while(v!=u);
    }
}

int cas=1,T,n,m,u,v,k;
int b[N];
int bet[4]={0,2,3,1};       ///bet[i]=j  j can win i
//int win[4]={0,3,1,2};       ///win[i]=j  i can win j

void solve(){
    for(int i=0;i<2*n;i++) if(!dfn[i]) tarjan(i);
    for(int i=0;i<2*n;i+=2) if(belong[i]==belong[i+1]){
        printf("no\n");
        return ;
    }
    printf("yes\n");
}

int main(){
    //freopen("in.txt","r",stdin);
    scanf("%d",&T);
    while(T--){
        init();
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++) scanf("%d",&b[i]);

        for(int i=0;i<m;i++){
            scanf("%d%d%d",&u,&v,&k);
            u--;v--;
            if(!k){
                if(bet[b[u]]!=bet[b[v]]){
                    addedge(u<<1,v<<1|1);
                    addedge(v<<1,u<1|1);
                }
                if(bet[b[u]]!=b[v]){
                    addedge(u<<1,v<<1);
                    addedge(v<<1|1,u<<1|1);
                }
                if(b[u]!=bet[b[v]]){
                    addedge(u<<1|1,v<<1|1);
                    addedge(v<<1,u<<1);
                }
                if(b[u]!=b[v]){
                    addedge(u<<1|1,v<<1);
                    addedge(v<<1|1,u<<1);
                }
            }
            else{
                if(bet[b[u]]==bet[b[v]]){
                    addedge(u<<1,v<<1|1);
                    addedge(v<<1,u<1|1);
                }
                if(bet[b[u]]==b[v]){
                    addedge(u<<1,v<<1);
                    addedge(v<<1|1,u<<1|1);
                }
                if(b[u]==bet[b[v]]){
                    addedge(u<<1|1,v<<1|1);
                    addedge(v<<1,u<<1);
                }
                if(b[u]==b[v]){
                    addedge(u<<1|1,v<<1);
                    addedge(v<<1|1,u<<1);
                }
            }
        }
        printf("Case #%d: ",cas++);
        solve();
    }
    return 0;
}
View Code

 

对建图还是有些时候比较懵逼。。还太弱

 

2-SAT 学习笔记

标签:

原文地址:http://www.cnblogs.com/luxiaoming/p/5778006.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!