ZOJ 3422 2-SAT

6 篇文章 0 订阅

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4106

Here is a procedure's pseudocode:

	   go(int dep, int n, int m)  
	   begin  
	      output the value of dep. 
	      if dep < m and x[a[dep]] + x[b[dep]] != c[dep] then go(dep + 1, n, m)
	   end 
	 

In this code n is an integer. abc and x are 4 arrays of integers. The index of array always starts from 0. Array a and b consist of non-negative integers smaller than n. Array xconsists of only 0 and 1. Array c consists of only 0, 1 and 2. The lengths of array ab and c are m while the length of array x is n.

Given the elements of array ab, and c, when we call the procedure go(0, n , m) what is the maximal possible value does the procedure output?

Input

There are multiple test cases. The first line of input is an integer T (0 < T ≤ 100), indicating the number of test cases. Then T test cases follow. Each case starts with a line of 2 integers n and m (0 < n ≤ 200, 0 < m ≤ 10000). Then m lines of 3 integers follow. The i-th(1 ≤ i ≤ m) line of them are ai-1 ,bi-1 and ci-1 (0 ≤ ai-1bi-1 < n, 0 ≤ ci-1 ≤ 2).

Output

For each test case, output the result in a single line.

Sample Input

3
2 1
0 1 0
2 1
0 0 0
2 2
0 1 0
1 1 2

Sample Output

1
1
2

题目大意:

              给定a,b,c,x四个数组。x只包含{0,1},c只包含{0,1,2,},a和b里面的元素都是从0-n-1的数,现要求这段代码中的dep的最大数                          go(int dep, int n, int m)  

	   begin  
	      output the value of dep. 
	      if dep < m and x[a[dep]] + x[b[dep]] != c[dep] then go(dep + 1, n, m)
	   end 
大体思路:
          对于每一个a[i]和b[i]值x[]都有一定的取值{0,1},当然x[a[i]]如果等于0就不能再等于其他的数,如果等于1了,也是同理。这就转化成了典型的2-sat问题,注意建边的规则,详见代码。
ps:我是改了,模板想用还得自己写,用别人的就是不靠谱。
#include <cstdio>
#include <iostream>
#include <string.h>
#include <cmath>
#include <stack>
using namespace std;
//=============================================================
//2-sat模板
const int maxn=505;
const int maxm=100005;
int n,m,a[maxm][3];
struct note
{
    int to;
    int next;
}edge[maxn*2*maxn];
int head[maxn];
int ip;
int dfn[maxn],low[maxn],sccno[maxn],cnt,scc,instack[maxn];
stack<int>stk;
void addedge(int u,int v)
{
    edge[ip].to=v,edge[ip].next=head[u],head[u]=ip++;
}
// x = xval or y = yval
void add_cluse(int x,int xval,int y,int yval)
{
    x=x*2+xval;
    y=y*2+yval;
    addedge(x,y^1);
    addedge(y,x^1);
}
void dfs(int u)
{
    dfn[u]=low[u]=++scc;
    stk.push(u);
    instack[u]=1;
    for (int i=head[u]; i!=-1; i=edge[i].next)
    {
        int v=edge[i].to;
        if (!dfn[v])
        {
            dfs(v);
            low[u]=min(low[u],low[v]);
        }
        else if (instack[v])
            low[u]=min(low[u],dfn[v]);
    }
    if (low[u]==dfn[u])
    {
        cnt++;
        int x;
        do
        {
            x=stk.top();
            stk.pop();
            sccno[x]=cnt;
            instack[x]=0;
        }while (x!=u);
    }
}
bool solve()
{
    scc=cnt=0;
    memset(sccno,0,sizeof(sccno));
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(instack,0,sizeof(instack));
    while (!stk.empty()) stk.pop();
    for (int i=0; i<2*n; i++) if (!dfn[i]) dfs(i);
    for (int i=0; i<2*n; i+=2)
    {
        if (sccno[i]==sccno[i^1]) return false;
    }
    return true;
}
//solve返回true证明2-sat有解,否则没解
//============================================================
void build(int mid)
{
    memset(head,-1,sizeof(head));
    ip=0;
    for(int i=0; i<mid; i++)
    {
        if(a[i][2]==0) add_cluse(a[i][0],0,a[i][1],0);
        if(a[i][2]==1)
        {
            add_cluse(a[i][0],1,a[i][1],0);
            add_cluse(a[i][0],0,a[i][1],1);
        }
        if(a[i][2]==2) add_cluse(a[i][0],1,a[i][1],1);
    }
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0; i<m; i++)
            scanf("%d%d%d",&a[i][0],&a[i][1],&a[i][2]);
        int l=0,r=m,num;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            build(mid);
            if(solve())
            {
                num=mid;
                //printf("(%d)\n",num);
                l=mid+1;
            }
            else
                r=mid-1;
        }
        printf("%d\n",num);
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
百度百科创建词条工具V2.7 我们先了解一下百度百科的优势: 1.权威性,广大网民对百度百科信任度特别高,容易受百科中相关信息影响 2.排名好,绝大部分百科词条(即关键词)能排至各大搜索引擎的前三位 3.流量大,一般词条每天浏览量不亚于一个中型企业站每天的总流量 4.转化率高,百科成为网民上网查资料必看的网站,转化为客户的几率较PPC及PM广告大得多。如病人及其家属查找某疾病如何治疗时,必看百科 5.长期有效,百科广告加上之后长期稳定有效,且不产生后续费用 ………   那么,百度百科创建词条工具可以提供哪些帮助呢? 1.创建百科词条,如品牌名、网站名、产品词、人名、公司名… 2.修改百科词条,在原有词条中加入您的内容,如广告内容、名片… 3.删除百科词条,删除不利词条内容或整个词条(不推荐使用) 4.百科内容撰写,根据客户要求编写词条内容 如有其他需求可及时与客服人员沟通,QQ:120962274 百度百科创建词条网站:www.uducn.com   百度百科创建词条常见错误: 1.修改词条原因不明确。例如:修改原因为“编辑词条”“不具体”“更完善”“更具体”等。 2.修改词条原因错误。例如:修改内容是添加图片,填写的修改原因为添加链接。 3.修改词条原因未能明确说明修改的具体区域。例如:修改了词条中的内容并添加了链接,修改原因应写明:添加内容以及链接,必须指出修改或删除的错误内容,并给出具体理由;只修改错别字,必须指明具体的错字;若您修改了表格中的内容,必须明确指出您修改了表格中的哪部分内容。 4.修改词条不可完全删除原词条的内容,可以选择性删除修改原词条内容。 5.编辑者误将角标误添加在段首,或误添加在了完整段落句号之前。   百度百科创建词条时请注意您的词条中不要有违背“百科原则”的内容,否则词条将被编辑删除,并扣除20分,情节严重者,“百科”有权对其做出关闭部分权限、暂停直至删除其帐号等处罚。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值