经典题目
注:As the time goes by,I have turned middle school student.So I'm short of time.From now on, I will not write comments in the code. It may not be satisfaction with you.Sorry.
目录
题目
- 1000ms
- 131072K
蒜头君热心公益,他想要在近期举办一场慈善晚宴,准备邀请一些社会名流前来,但社会名流都是成双入对的,蒜头君自己是单身汉,所以他只想每一对夫妻来一个人,社会名流之间的关系比较复杂,有些人之间关系不好,他们不想同时出现,当然夫妻之间不会是关系不好的,蒜头君想知道有没有一种方案使得每一对夫妻都有一个人参加晚宴。
输入格式
第一行两个整数 n,mn,m(1≤n≤104,1≤m≤105),表示社会名流夫妻数和关系不好的关系数;
接下来 mm 行,每行四个整数 A1,A2,C1,C2,每两个数之间用一个空格隔开,A1,A2 表示夫妻编号,编号从 0 开始,C1,C2 表示是夫妻之中的哪一个人,其中值为 0 时表示丈夫,值为 1 时表示妻子。
输出格式
输出一行,如果存在一种合适的方案,输出
"YES"
,否则输出"NO"
。格式说明
输出时每行末尾的多余空格,不影响答案正确性
输入、输出要求
要求使用「文件输入、输出」的方式解题,输入文件为
charitable.in
,输出文件为charitable.out
样例输入
2 10 1 0 1样例输出
YES
题目解释:A1 A2表示有两对夫妻A1和A2之间有人有矛盾,C1表示有矛盾的人是夫妻A1中的夫还是妻,C2表示有矛盾的人是夫妻A2中的夫还是妻
题解:
知识点:2-SAT问题
分析:
这是一个非常经典的 2-SAT 问题,一队夫妻可以看作一个 xi=0/1 的 01 变量。也就是说,这里的2-SAT问题是将true和false两大集合变成了妻子和丈夫两大集合
这道题是用 2-SAT 描述“反对”关系,也就是:
两人关系不好,就把一个人向另一个人的伴侣连一条边(即一个人去了,与他关系不好的人就一定不能去,由题意得与他关系不好的人的伴侣就必须要去,“否则会吃饱【DOGE】”),然后进行 2-SAT,先尝试选丈夫,不行的话就选妻子,都不行的话就是"NO"
,最后每一对都能选出一个人的话就是"YES"
。
如果你不会基础的 2-SAT 模板,可以去相关的课程学习,或者去网上搜索相关博客。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<set>
using namespace std;
const int N=2e4+5,M=2e5+5;
int n,m;
int e[M],ne[M],h[N],idx;
int selected[N],c,S[N];
inline void c_plus(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
}
inline void init(){
idx=0;
memset(h,-1,sizeof(h));
}
inline void add(int a,int b){
e[idx]=b;
ne[idx]=h[a];
h[a]=idx++;
}
bool dfs(int u){
if (selected[u^1]){
return false;
}
if (selected[u]){
return true;
}
selected[u]=true;
S[c++]=u;
for (int i=h[u];~i;i=ne[i]){
int v=e[i];
if (!dfs(v)){
return false;
}
}
return true;
}
bool Two_SAT(){
for (int i=0;i<(n<<1);i+=2){
if (!selected[i] && !selected[i+1]){
c=0;
if (!dfs(i)){
while (c>0){
selected[S[--c]]=false;
}
if (!dfs(i+1)){
return false;
}
}
}
}
return true;
}
int main(){
freopen("charitable.in","r",stdin);
freopen("charitable.out","w",stdout);
c_plus();
init();
cin>>n>>m;
while (m--){
int a1,a2,c1,c2;
cin>>a1>>a2>>c1>>c2;//a为a1夫妻,b为a2夫妻
int a[2]={(a1<<1),(a1<<1)+1},b[2]={(a2<<1),(a2<<1)+1};
add(a[c1],b[c2^1]);
add(b[c2],a[c1^1]);
}
if (Two_SAT()){
puts("YES");
}else{
puts("NO");
}
return 0;
}