HDOJ3715-Go Deeper二分+2-sat解题报告

链接:http://acm.hdu.edu.cn/showproblem.php?pid=3715用a[i]表示a[i]对应的x[a[i]]是0,a[i]+n表示是1,则

当c[i]=0时,不能同时为0,则a[i]->b[i]+n,b[i]->a[i]+n

当c[i]=1时,a[i]->b[i],b[i]->a[i],a[i]+n->b[i]+n,b[i]+n->a[i]+n;

当c[i]=2时,a[i]+n->b[i],b[i]+n->a[i];

最后如果二分枚举深度值,要用到二分枚举

View Code
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 205
#define M 10005
using namespace std;
int head[2*N],t;
int dfn[2*N],sc[2*N];
int stk1[2*N],stk2[2*N],cnt0,cnt1,top1,top2;
int a[M],b[M],c[M];
struct node
{
    int v,next;
};
node edge[M*4];
void init()
{
    t=0;
    cnt0=cnt1=0;
    top1=top2=0;
    memset(head,-1,sizeof(head));
    memset(dfn,-1,sizeof(dfn));
    memset(sc,-1,sizeof(sc));
}
void add(int u,int v)
{
    edge[t].v=v;
    edge[t].next=head[u];
    head[u]=t++;
}
void build(int mid,int n)
{
    int i;
    for(i=1;i<=mid;i++)
    {
        if(c[i]==0)
        {
            add(a[i],b[i]+n);
            add(b[i],a[i]+n);
        }
        else if(c[i]==1)
        {
            add(a[i],b[i]);
            add(a[i]+n,b[i]+n);
            add(b[i],a[i]);
            add(b[i]+n,a[i]+n);
        }
        else
        {
            add(a[i]+n,b[i]);
            add(b[i]+n,a[i]);
        }
    }
}
void gabow(int u)//gabow算法求强连通分量
{
    dfn[u]=cnt0++;
    stk1[top1++]=u;
    stk2[top2++]=u;
    int i,j,v;
    for(i=head[u];i>=0;i=edge[i].next)
    {
        v=edge[i].v;
        if(dfn[v]==-1)
        gabow(v);
        else if(sc[v]==-1)
        while(dfn[stk2[top2-1]]>dfn[v])
        top2--;
    }
    if(stk2[top2-1]!=u)
    return;
    top2--;
    do
    {
        sc[stk1[--top1]]=cnt1;
    }while(stk1[top1]!=u);
    cnt1++;
}
int can(int mid,int n)
{
    init();
    build(mid,n);
    int i;
    for(i=0;i<2*n;i++)
    if(dfn[i]==-1)
    gabow(i);
    for(i=0;i<n;i++)
    if(sc[i]==sc[i+n])
    return false;
    return true;
}
int main()
{
    int n,m,i,j,ans,low,high,mid;
    int tcase;
    scanf("%d",&tcase);
    while(tcase--)
    {
        scanf("%d%d",&n,&m);
        for(i=1;i<=m;i++)
        scanf("%d%d%d",&a[i],&b[i],&c[i]);
        low=1,high=m;
        ans=1;
        while(low<=high)
        {
            mid=(low+high)>>1;
            if(can(mid,n))
            {
                ans=mid;
                low=mid+1;
            }
            else
            high=mid-1;
        }
        printf("%d\n",ans);
    }
    return 0;
}

 

posted @ 2012-08-15 19:21  zhenhai  阅读(153)  评论(0编辑  收藏  举报