POJ 1291 This Sentence is False 并查集应用

This Sentence is False
Time Limit: 1000MS
Memory Limit: 65536K
Total Submissions: 859
Accepted: 370

Description

The court of King Xeon 2.4 is plagued with intrigue and conspiracy. A document recently discovered by the King's Secret Service is thought to be part of some mischievous scheme. The document contains simply a set of sentences which state the truth or falsehood of each other. Sentences have the form "Sentence X is true/false" where X identifies one sentence in the set. The King's Secret Service suspects the sentences in fact refer to another, yet uncovered, document. 
While they try to establish the origin and purpose of the document, the King ordered you to find whether the set of sentences it contains is consistent, that is, if there is a valid truth assignment for the sentences. If the set is consistent, the King wants you to determine the maximum number of sentences which can be made true in a valid truth assignment for the document.

Input

The input contains several instances of documents. Each document starts with a line containing a single integer, 
N, which indicates the number of sentences in the document (1 <= N <= 1000). The following N lines contain each a sentence. Sentences are numbered sequentially, in the order they appear in the input (the first is sentence 1, the second is sentence 2, and so on). Each sentence has the form "Sentence X is true." or "Sentence X is false.", where 1 <= X <= N. The value N = 0 indicates the end of input.

Output

For each document in the input your program should output one line. If the document is consistent,your program should print the maximum number of sentences in a valid truth assignment for the document.Otherwise your program should print the word 'Inconsistent'.

Sample Input

1
Sentence 1 is false.
1
Sentence 1 is true.
5
Sentence 2 is false.
Sentence 1 is false.
Sentence 3 is true.
Sentence 3 is true.
Sentence 4 is false.
0

Sample Output

Inconsistent
1
3

Source


这一题是并查集来解,好像也可以用2-Sat来解

每句话有两种可能的身份, 一个是说谎者, 一个是说真话。如果X说Y在说谎,那么X和Y的身份一定不同。使用并查集,将已知身份相对关系的句子并到一起。维护并查集的父向量,在同一个集合中的任何两个句子身份的相对关系都是可以根据父向量求出的。每个集合的根都可能有两种身份,一旦根的身份确定了,其他节点的身份就都确定了。最后只要最大化每个集合说真话者的个数就能求得答案。

代码如下:

#include <iostream>
#include <fstream>
#include <cstring>
#include <cstdio>
using namespace std;

const int maxn = 1010;
int parent[maxn],t[maxn],f[maxn];
bool status[maxn];//status[k]表示子节点与双亲节点状态是否相同,1表示相同,0表示不同
int find(int k)
{
    if(parent[k]<0)
        return k;
    int t = find(parent[k]);
    status[k]=status[k]?status[parent[k]]:!status[parent[k]];//根据双亲节点状态,更改子节点状态
    parent[k]=t;
    return t;
}
bool merge(int a,int b,bool isT)//isT表示两个句子之间是说真,还是假
{
    int l = find(a);
    int r = find(b);
    if(l==r)
    {
        if(status[a]==status[b])//如果a,b的状态相同,则根据isT来判断是否相悖,如果a说b假,那就相悖
            return isT;
        else//如果a,b的状态不同,如果a说b真,那就相悖
            return !isT;
    }
    if(status[a]==status[b])//根据a,b的状态是否相同和a与b之间的真假声明,来改变l集合根节点的状态
        status[l]=isT;
    else
        status[l]=!isT;
    parent[l]=r;
    return true;
}
int main()
{
    freopen("in.txt","r",stdin);
    int n;
    int i,j,r;
    char str[10];
    while(scanf("%d",&n)&&n!=0)
    {
        memset(status,1,n+1);//使根节点状态为1
        memset(parent,-1,sizeof(int)*(n+1));
        bool flag = true;
        for(i=1; i<=n; i++)
        {
            getchar();
            scanf("Sentence %d is %s",&j,str);
            if(flag&&str[0]=='t')
                flag=merge(i,j,1);//表示i说j为真
            if(flag&&str[0]=='f')
                flag=merge(i,j,0); //表示i说j为假
        }
        if(!flag)
            printf("Inconsistent\n");
        else
        {
            int ans=0;
            memset(t,0,sizeof(int)*(n+1));
            memset(f,0,sizeof(int)*(n+1));
            for(int k=1; k<=n; k++)//找出各个节点的根节点来代表该集合,并统计1的个数和0的个数
            {
                r = find(k);
                if(status[k])
                    t[r]++;
                else
                    f[r]++;
            }
            for(int k=1; k<=n; k++)//将各集合的max(1的个数,0的个数)加起来
                ans+=max(t[k],f[k]);
            printf("%d\n",ans);
        }
    }
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值