URAL 2017 Best of a bad lot 二分图染色 使x集点数最少

题目链接:点击打开链接

题意:

有n个嫌疑犯。[1,n]

第i行表示第i个嫌疑犯说案发时他所在的地名,后面一个数m表示当时他看到m个人,后面m个数表示他看到的人。

找出最小的犯罪团体(即多数人都是好人原则)

若大家都是好人则随便输出一个人当坏人==

思路:

当一个人x被2个不同地方的人u, v看到时,则u v其中一个一定是犯人。

所以u-v建一条边。

然后二分图染色使得x点集点数最少。

先染一个子图,然后把点集少的归成x集就可以了,因为任意两个子图都是互不影响的。

#include<bits/stdc++.h>
using namespace std;
template <class T>
inline bool rd(T &ret) {
	char c; int sgn;
	if (c = getchar(), c == EOF) return 0;
	while (c != '-' && (c<'0' || c>'9')) c = getchar();
	sgn = (c == '-') ? -1 : 1;
	ret = (c == '-') ? 0 : (c - '0');
	while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
	ret *= sgn;
	return 1;
}
template <class T>
inline void pt(T x) {
	if (x <0) {
		putchar('-');
		x = -x;
	}
	if (x>9) pt(x / 10);
	putchar(x % 10 + '0');
}
const int N = 450;
vector<int>D[N], G[N];
map<string, int> mp;
int local[N], n;
void input(){
    for(int i = 1; i <= n; i++){
        D[i].clear(); G[i].clear();
    }
    mp.clear(); string u; int siz = 1;
    for(int i = 1, loc, v; i <= n; i++)
    {
        cin>>u;
        if(mp.count(u)) loc = mp[u];
        else mp[u] = loc = siz++;
        local[i] = loc;
        rd(loc);
        while(loc--){
            rd(v);
            D[v].push_back(i);
        }
        D[i].push_back(i);
    }
}
void build(){
    for(int i = 1; i <= n; i++)
        for(int j = 0; j < D[i].size(); j++)
            for(int k = j + 1; k < D[i].size(); k++)
            {
                int u = D[i][j], v = D[i][k];
                if(local[u]!=local[v])
                    G[u].push_back(v), G[v].push_back(u);
            }
}
int vis[N];
vector<int>col[2], one, ans;
void bfs(int x){
    col[0].clear(); col[1].clear();
    col[0].push_back(x);
    vis[x] = 0;
    queue<int>q; q.push(x);
    while(!q.empty()){
        int u = q.front(); q.pop();
        for(int i = 0; i < G[u].size(); i++)
        {
            int v = G[u][i];
            if(vis[v] == -1)
            {
                vis[v] = !vis[u];
                q.push(v);
                col[vis[v]].push_back(v);
            }
        }
    }
    int mx = col[0].size()<col[1].size()? 0 : 1;
    for(int i = 0; i < col[mx].size(); i++)
        ans.push_back(col[mx][i]);
}
int main(){
	while (~scanf("%d", &n)){
		input();
        build();
        memset(vis, -1, sizeof vis);
        ans.clear();
        for(int i = 1; i <= n; i++)
            if(vis[i] == -1)
                bfs(i);
        if(ans.size() == 0)ans.push_back(1);
        pt(ans.size()); puts("");
        for(int i = 0; i < ans.size(); i++)
            printf("%d%c", ans[i], i+1==ans.size()? '\n':' ');

	}
	return 0;
}
时间: 2024-11-07 17:42:59

URAL 2017 Best of a bad lot 二分图染色 使x集点数最少的相关文章

[AtCoder Code Festival 2017 QualB C/At3574] 3 Steps - 二分图染色,结论

给你一个n个点m条边的无向图,进行以下操作 如果存在两个点u和v,使得从u走三步能恰好到达v,那么在u和v之间连接一条边 重复这个操作直到不能再连接新的边,问最后有多少条边? n, m <= 100000 如果一个连通块包含奇环它一定会变成完全图 如果一个连通块没有奇环,那么它一定是二分图,二分图一定会变成"完全二分图" #include <bits/stdc++.h> using namespace std; #define int long long const

【巨坑】 二分图学习笔记 [2017年6月计划 学习二分图]

1.二分图:    ①把一个图的点集划为两个不相交的集合U,V,使得每一条边都连接U,V中的节点. ②(等价定义,更方便看)不含边数为奇数的环的图 2.匹配(matching): 边集,每一条边所连顶点互不相同 3.最大匹配: 所含边数最大的匹配 4.完美匹配: 所有顶点都被匹配,完美匹配一定是最大匹配. 5.交替路: 从一个非匹配点出发,依次走非匹配边,匹配边,非匹配边....交替走,形成交替路 6.增广路: 从一个非匹配点出发,走交替路,经过另一个非匹配点,则这条路径叫做增广路   增广路特

noip 2010 关押罪犯 (二分图染色 并茶几)

/* 二分图染色版本 两个监狱对应二部图的两部分 在给定的怨气值里二分 对于每一个Ci 进行染色判断是否合法 染色的时候 如果这条边的ci > Ci 这两个人就带分开 即染成不同的颜色 如果染色到某两个点颜色相同且怨气值>Ci 这个Ci就不合法 二分直到最后答案 */ #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100

【hiho】hiho第三十周&#183;二分图染色判定

是时候认真学学二分图了... 光会模板没用的,打好基础最重要~ 题目: 字面意思,二分图染色判断,判断是否是二分图 思路: 要让该无向图成为一张二分图,必须得将点划为G1,G2两个集合 也就是,对于给定的任何一条边,其连接的两个节点不能同色 那么我们可以总结出一个方法: 对于当前结点: 1.若其未被染色,我们规定将其染成A色,记为1 2.遍历其所有相邻的染色点,有未染色的,染为B色,记为2,DFS之 注:一旦被染色,说明此点状态被唯一确定 那么我们可以得到判断条件: 1.染色过程是否发生冲突 附

UVA11080- Place the Guards(二分图染色)

题目链接 题意:放最少的士兵去监视所有的道路, 但士兵不可相邻,符合的话,就输出最少的士兵数,否则输出-1 思路:其实就是二分图染色,即黑白染色,然后选择黑白染色最少的那个颜色累加,但要注意可能有多个连通块,只要有一个连通块不符合的话,就不符合. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <vector> #include <algorithm> u

洛谷P1330 封锁阳光大学(二分图染色)

P1330 封锁阳光大学 题目描述 曹是一只爱刷街的老曹,暑假期间,他每天都欢快地在阳光大学的校园里刷街.河蟹看到欢快的曹,感到不爽.河蟹决定封锁阳光大学,不让曹刷街. 阳光大学的校园是一张由N个点构成的无向图,N个点之间由M条道路连接.每只河蟹可以对一个点进行封锁,当某个点被封锁后,与这个点相连的道路就被封锁了,曹就无法在与这些道路上刷街了.非常悲剧的一点是,河蟹是一种不和谐的生物,当两只河蟹封锁了相邻的两个点时,他们会发生冲突. 询问:最少需要多少只河蟹,可以封锁所有道路并且不发生冲突. 输

CODEVS1022 覆盖 (二分图染色+匈牙利算法)

先对整幅图进行二分图染色,再跑一遍匈牙利算法. 1 /* CODEVS1022 */ 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #include <cmath> 6 7 #define maxn 10008 8 9 struct edge{ 10 int u,v,next; 11 }eg[maxn*4]; 12 13 int dx[4]={0,0,1,-1}; 14 i

POJ2942 Knights of the Round Table[点双连通分量|二分图染色|补图]

Knights of the Round Table Time Limit: 7000MS   Memory Limit: 65536K Total Submissions: 12439   Accepted: 4126 Description Being a knight is a very attractive career: searching for the Holy Grail, saving damsels in distress, and drinking with the oth

[NOIP2010]关押罪犯(二分+二分图染色)

传送门 大意:我们把图分为两部分,使得两部分中的内部边的最大权值最小. 思路:哎,拿到题的时候想了二分图染色,发现不好做,但我没有想到二分,只好最后去骗了一个30分.正确的思路是:首先我们要 去二分最大的冲突边的是哪一条(按照权值二分),因为当二分的边权增大时,连的边也就越少,连通块的数目就越多,冲突就越少,所以边权是可以二分的,在二分过后用二分图判定,如果可以染成二分图即为可行的解. 代码: #include<cstdio> #include<algorithm> #includ