URAL 2017 Best of a bad lot(二分图交叉染色)

2017. Best of a bad lot

Time limit: 1.0 second
Memory limit: 64 MB
A cruise liner hasn’t moved away from the land even for three miles when it became apparent that somebody has drowned one of the stewards in the swimming pool. The captain promised to make an investigation personally and to throw the villains overboard. He is going to find the group of murderers by asking each of n passengers two following questions.
  1. Where were you at the moment of departure?
  2. Who did you see there?
The captain will make his decision based on contradictions in passengers’ testimonies. For example, if one passenger says that he was in his room, and another passenger says that he saw the first one near the swimming pool, then one of these two is for sure mixed up with murder. However, if passenger A didn’t see some other passenger B at the place, where passenger B really was, the captain wouldn’t consider it a contradiction, because passenger B could have just been unnoticed there.
The investigation is unlikely to be reliable, because the murderers have agreed that their testimonies will have no contradictions between them. As for the honest people, they have nothing to hide and will tell only the truth. You volunteered to compare the mismatches in the passengers’ answers and reveal a group of suspects. Moreover, you want to give out to the captain the smallest possible group of passengers. If somebody has to become the feeding stuff for sharks today, let as few people as possible suffer.

Input

The first line contains an integer n that is the number of the passengers (2 ≤ n ≤ 400). Next n lines contain the testimonies of each of the passengers. The i-th line starts with the place where the i-th passenger said he was at the moment of departure that is a non-empty string up to twenty lowercase Latin letters long. The place is followed by the list of the passengers the i-th passenger saw there in the form m n 1  n 2 …  n m (0 ≤ mn − 1; 1 ≤ n jn; n ji; n j < n j+1).

Output

In the first line output a positive integer that is the number of the passengers in the suspect group. In the second line output the numbers of these suspects in any order. If the problem has several solutions, output any of them. It is guaranteed that at least one solution exists.

Samples

inputoutput
3
bar 0
bar 1 1
pool 2 1 2
1
3
3
pool 2 2 3
pool 2 1 3
pool 2 1 2
1
1

Notes

In the first example it is possible that both the first and the second passengers are murderers, and the third one tells the truth. But it is also possible that the first two tell the truth and the third one is a murderer. It is needed to output the second possibility since the group of suspects in it is smaller.
In the second example all passengers do not have testimony contradictions, so any of them could be a murderer.
Problem Author: Oleg Dolgorukov
Problem Source: NEERC 2014, Eastern subregional contest



        好久没有系统的弄图论,今天遇到这要一道二分图的题捡了好久……

        大致题意:一艘邮轮上除了杀人案,然后让你断案,对于每一个船上的人,我们问两个问题,第一是当时他在哪,以及在那个地方看见了谁。然后只要两个人有矛盾,那么我们就认为这两个人中一定有一个人是其中一个嫌疑人。现在让你确定一个最小的范围,使得嫌疑人的数量尽可能少,并输出任意一种嫌疑人方案。这里特别说明,嫌疑人知道你会这么判断,所以嫌疑人之间会统一口供,然后好人也没有必要去撒谎。

        首先,我们要确定如何判定两个人是否有矛盾。一开始,我认为,如果A自己说的所在地点与B陈述的A的所在地点不同,那么A与B有矛盾。这样判断是正确的,但是会漏掉一些情况。对于两个点u和v,如果两个人不相互陈述对方的地点,我们不能因此断定他俩没有矛盾,因为如果u和v的地点不同,然后u和v都宣称看到了x,那么u和v也是矛盾的。故正确的判断方法是,首先把每个人看到的人的列表中加上自己,然后枚举任意不在统一地点的两个人,看他俩是否有宣称看到同一个人,如果有那就有矛盾,否则没有。

        判断矛盾之后,很自然而然的,我们会想到连接有矛盾的边,表示该边的两端至少一个是嫌疑人。如此之后,相当于我们要在这个图中找一个最大独立集,于是开始往二分图匹配方向上思考,但是匹配无法解决方案数的输出问题(对于一个匹配,我们并不知道确定哪一个人为罪犯)。于是得换一种想法,二分图Emmm……我们这时再认真读一下题目,我们就会注意到,罪犯之间统一口供,然后好人也没必要撒谎。这就意味着,如果a与b有矛盾,b与c有矛盾,那么a与c一定没有矛盾,即图具有“反传递性”。为什么呢?假设b是嫌疑人,那么a与c不是嫌疑人而是好人,而好人没必要撒谎,所以a与c一定没有矛盾;假设b不是嫌疑人,那么a和c都是嫌疑人,由于嫌疑人统一了口供,所以说嫌疑人之间也不会存在矛盾,那么a与c也一定没有矛盾。故在以上条件下a与c没有矛盾,也就意味着这个原图可以直接转换成一个二分图。

        于是我们就可以把点分成两类,一类为好人,一类为嫌疑犯。既然可以人为的分组,那么我们就可以贪心的解决这个问题。由于这个矛盾关系不一定保证是一个连通图,所以说可以看作是很多个二分子图。对于每一个子图,我们可以用交叉染色法分成两组,而这两组具体哪个定义为好人,哪个为嫌疑人,也是由我们自己决定的,所以我们当然是把人多的那一组定为好人,少的定为嫌疑人。对所有子图这么做即可解出此题。

        然后,再总结一些二分图的具体知识。对于二分图的判定,我们就可以用我生造出来的“反传递性”来判定,编程实现的话可以用交叉染色法。具体分配也是用这个方法。然后此题看似是用了交叉染色法解决了最大独立集的问题,但是实际上是不能的。特殊之处在于本题的图不是固定的,我可以自由的分配两部分中哪一部分是在左边,哪一部分是在右边的。真正要求最大独立集,还是要用n-最大匹配数。具体见代码:

#include<bits/stdc++.h>
#define N 410
using namespace std;

struct node
{
    string place;
    bool v[N];
} p[N];

vector<int> g[N],res[2],ans;
bool v[N]; int n;

void dfs(int x,int wh)
{
    v[x]=1;
    res[wh].push_back(x);
    for(int i=0;i<g[x].size();i++)
    {
        int y=g[x][i];
        if (!v[y]) dfs(y,wh^1);
    }
}

int main()
{
	while (~scanf("%d", &n))
    {
        ans.clear();
        memset(v,0,sizeof(v));
        memset(g,0,sizeof(g));
		for(int i=1;i<=n;i++)
        {
            int x,y;
            cin>>p[i].place;
            scanf("%d",&x); p[i].v[i]=1;
            while(x--)
            {
                scanf("%d",&y);
                p[i].v[y]=1;
            }
        }
        for(int i=1;i<=n;i++)
            for(int j=i+1;j<=n;j++)
            {
                if (p[i].place==p[j].place) continue;
                for(int k=1;k<=n;k++)
                    if (p[i].v[k]&&p[j].v[k])
                    {
                        g[i].push_back(j);
                        g[j].push_back(i);
                    }
            }
        for(int i=1;i<=n;i++)
            if (!v[i])
            {
                memset(res,0,sizeof(res));dfs(i,0);
                int wh=res[0].size()>res[1].size();
                for(int j=0;j<res[wh].size();j++)
                    ans.push_back(res[wh][j]);
            }
        if (!ans.size()) ans.push_back(1);
        printf("%d\n",(int)ans.size());
        for(int i=0;i<ans.size();i++)
            printf("%d ",ans[i]);
        puts("");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值