hdu 1824 && hdU 3062 2-SAT经典

 

/*
HDU 3062
*/
#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<cmath>  
#include<queue>  
#include<stack>  
#include<map>  
#include<algorithm>  
using namespace std;  
const int MAXE=100000002;  
const int MAX=6009;  

struct EDGE    
    {    
        int v; // 从u点出发能到达的点v    
        int next; // 从u点出发能到达的下一条边的编号    
    }edge[MAXE];    
    int first[MAX];   // first[u] = e:从点u出发的最后一条边的编号是e(“最后”是指最后输入)    
    int dfn[MAX];  // dfn[u]:节点u搜索的次序编号(时间戳)    
    int low[MAX];// low[u]:是u或u的子树能够追溯到的最早的栈中节点的次序号    
    int ins[MAX];// 是否在栈中    
    int scc[MAX]; // scc[i] = j:第i个点所在的强连通分量的编号  (此题可有可无)  
    int t,n,m;    
    int num; // 强连通分量的数目    
    int index; // 次序编号    
    int s[MAX];    
    int top,e;
	int a,b,c,d,nn;
    int DFS(int x)    
    {    
        low[x]=dfn[x]=index++;    
        s[++top]=x;    
        ins[x]=1;    
        // 枚举每一条边:u-->v    
        for(int k=first[x];k!=-1;k=edge[k].next)    
        {    
            int v=edge[k].v;    
            if(dfn[v]==0)    
            {    
   
                DFS(v);    
                low[x]=min(low[x],low[v]);   
            }    
            else if(ins[v])    
            {    
                low[x]=min(dfn[v],low[x]);   
 
            }    
        }    
         // 如果节点u是强连通分量的根    
        if(low[x]==dfn[x])    
        {    
            int v;    
            num++;    
            do{    
            v=s[top--];     
            ins[v]=0;    
            scc[v]=num;    
            }while(v!=x);    
        }    
        return 1;  
    }
    
inline void add(int u,int v)
{
    edge[e].v=v;
    edge[e].next=first[u];
    first[u]=e++;
}  
inline int turn(int x)
{
	return x>n?x-n:x+n;
}
void init()
{
	 memset(dfn,0,sizeof(dfn));    
     memset(low,0,sizeof(low));    
     memset(first,-1,sizeof(first));    
   //  memset(ins,0,sizeof(ins));     
     index=1;  
     top=-1;
     num=0;    
     e=0;
	 int aa,bb;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&a,&b,&c,&d);
		a++;
		aa=a+c*n;
		b++;
		bb=b+d*n;
		add(aa,turn(bb));
		add(bb,turn(aa));
    }

}

bool check()
{
    for(int i=1;i<=n;i++)
    if(scc[i]==scc[i+n])
    return false;
    return true;
}
void solve()  
{  
        for(int i=1;i<=2*n;i++)  
        {  
            if(dfn[i]==0)  
            {  
            DFS(i);  
            }  
        }  
        if(check())puts("YES");
		else puts("NO");
}  
int main()  
{  
    while(scanf("%d",&n)!=EOF)
    {
		scanf("%d",&m);
        init();
        solve();
    }
    return 0;  
}  

/*
HDU 1824
*/
#include<iostream>  
#include<cstdio>  
#include<cstring>  
#include<cmath>  
#include<queue>  
#include<stack>  
#include<map>  
#include<algorithm>  
using namespace std;  
const int MAXE=1000002;  
const int MAX=6009;  

struct EDGE    
    {    
        int v; // 从u点出发能到达的点v    
        int next; // 从u点出发能到达的下一条边的编号    
    }edge[MAXE];    
    int first[MAX];   // first[u] = e:从点u出发的最后一条边的编号是e(“最后”是指最后输入)    
    int dfn[MAX];  // dfn[u]:节点u搜索的次序编号(时间戳)    
    int low[MAX];// low[u]:是u或u的子树能够追溯到的最早的栈中节点的次序号    
    int ins[MAX];// 是否在栈中    
    int scc[MAX]; // scc[i] = j:第i个点所在的强连通分量的编号  (此题可有可无)  
    int t,n,m;    
    int num; // 强连通分量的数目    
    int index; // 次序编号    
    int s[MAX];    
    int top,e;
    int a,b,c;
    int DFS(int x)    
    {    
        low[x]=dfn[x]=index++;    
        s[++top]=x;    
        ins[x]=1;    
        // 枚举每一条边:u-->v    
        for(int k=first[x];k!=-1;k=edge[k].next)    
        {    
            int v=edge[k].v;    
            if(dfn[v]==0)    
            {    
   
                DFS(v);    
                low[x]=min(low[x],low[v]);   
            }    
            else if(ins[v])    
            {    
                low[x]=min(dfn[v],low[x]);   
 
            }    
        }    
         // 如果节点u是强连通分量的根    
        if(low[x]==dfn[x])    
        {    
            int v;    
            num++;    
            do{    
            v=s[top--];     
            ins[v]=0;    
            scc[v]=num;    
            }while(v!=x);    
        }    
        return 1;  
    }
    
inline void add(int u,int v)
{
    edge[e].v=v;
    edge[e].next=first[u];
    first[u]=e++;
}  
 
void init()
{
     memset(dfn,0,sizeof(dfn));    
     memset(low,0,sizeof(low));    
     memset(first,-1,sizeof(first));    
   //  memset(ins,0,sizeof(ins));     
     index=1;  
     top=-1;
     num=0;    
     e=0;
    for(int i=1;i<=t;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        a++;
        b++;
        c++;
        add(a+n,b);
        add(a+n,c);
        add(b+n,a);
        add(c+n,a);
    }
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&a,&b);
        a++;
        b++;
        add(a,b+n);
        add(b,a+n);
    }
}

bool check()
{
    for(int i=1;i<=n;i++)
    if(scc[i]==scc[i+n])
    return false;
    return true;
}
void solve()  
{  
        for(int i=1;i<=2*n;i++)  
        {  
            if(dfn[i]==0)  
            {  
            DFS(i);  
            }  
        }  
        if(check())puts("yes");
        else puts("no");
}  
int main()  
{  
    while(scanf("%d%d",&t,&m)!=EOF)
    {
        n=3*t;
        init();
        solve();
    }
    return 0;  
}  

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值