2-SAT(Tarjan)—— Get Luffy Out *(HDU 1816)

来源:互联网 发布:头发多久洗一次 知乎 编辑:程序博客网 时间:2024/06/06 08:55
  • 题目链接:
    http://acm.hdu.edu.cn/showproblem.php?pid=1816

  • 分析:
    和POJ 2723差不多,不过每把钥匙可以属于多个组了。

  • 题解:

    对立关系:一把钥匙用或者不用

    矛盾关系:如果一扇门上的一把锁不能被打开,那么另外一把锁肯定能被打开。一个钥匙被使用,和它同组的钥匙就肯定不能被使用

    根据矛盾关系建边,根据对立关系判断有无解。

  • AC代码:
    这里写图片描述

/*************************************************************************    > File Name: test.cpp    > Author: Akira     > Mail: qaq.febr2.qaq@gmail.com  ************************************************************************/#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include <algorithm>#include <queue>#include <stack>#include <map>#include <cmath>#include <vector>#include <set>#include <list>#include <ctime>typedef long long LL;typedef unsigned long long ULL;typedef long double LD;#define MST(a,b) memset(a,b,sizeof(a))#define CLR(a) MST(a,0)#define Sqr(a) ((a)*(a))using namespace std;#define MaxN 2333*4#define MaxM MaxN*10#define INF 0x3f3f3f3f#define bug cout<<88888888<<endl;#define MIN(x,y) (x<y?x:y)#define MAX(x,y) (x>y?x:y)int N, M;int kl[MaxN];int kr[MaxN];int dl[MaxM];int dr[MaxM];struct Edge{    int from,to,next;}edge[MaxM];int head[MaxN],cont;int low[MaxN];int dfn[MaxN];int Stack[MaxN], top;int belong[MaxN];int inStack[MaxN];int Index, cnt;void init(){    MST(head,-1);    MST(dfn,-1);    CLR(low);    CLR(inStack);    cont=0;    Index = cnt = 1;    top=0;}void add(int u,int v){    edge[cont].from = u;    edge[cont].to=v;    edge[cont].next=head[u];    head[u]=cont++;}void Tarjan(int x){    low[x] = dfn[x] = Index;                // 刚搜到一个节点时low = dfn    Index++;    Stack[++top] = x;                       // 将该节点入栈    inStack[x] = 1;                         // 将入栈标记设置为1    for(int i=head[x];i!=-1;i=edge[i].next)    {        int v=edge[i].to;        if(dfn[v ]== -1)        {            Tarjan(v);            low[x]=MIN(low[x], low[v]);     // 回溯的时候改变当前节点的low值        }        else if(inStack[v])        {            low[x] = MIN(low[x], dfn[v]);   // 更新当前节点的low值,这里的意思是两个节点之间有一条可达边,        }    }    if(low[x] == dfn[x])    {        for(int v=-1;v!=x;top--)        {            v = Stack[top];            inStack[v] = false;            belong[v] = cnt;        }        cnt++;    }}int main(){    while(~scanf("%d%d", &N, &M) && (N+M) )    {        int a,b;        for(int i=0;i<N;i++)        {            scanf("%d%d", &kl[i], &kr[i]);        }         for(int i=0;i<M;i++)         {            scanf("%d%d", &dl[i], &dr[i]);        }        int low = 0, high = M;        int mid = (low+high)>>1, ans = mid;        while(low <= high)        {            init();            for(int i=0;i<N;i++)            {                add(kl[i], kr[i]+2*N);                add(kr[i], kl[i]+2*N);            }            for(int i=0;i<mid;i++)            {                add(dl[i]+2*N, dr[i]);                add(dr[i]+2*N, dl[i]);            }            for(int i=0;i<4*N;i++)                if(dfn[i]==-1)                    Tarjan(i);            int flag = 0;            for(int i=0;i<2*N;i++)            {                if(belong[i] == belong[i+2*N])                {                    flag = 1;                    break;                }                if(flag) break;            }            if(flag) high = mid-1;            else low = (ans = mid)+1;            mid = (low+high)>>1;        }        cout << ans << endl;    }    system("pause");}
0 0