欢迎关注更多精彩
关注我,学习常用算法与数据结构,一题多解,降维打击。
题目大意
https://codeforces.com/contest/1239/problem/D
有n个住户,每个住户有且只有一只猫,有的住户是认识别的住户的猫。
现在需要选出x个住户和y只猫(x>0, y>0),
使得x+y=n且所有被选中住户都不认识任何一只被选中的猫。
分析&思路
对于每一家要么选人,要么选猫,是一个2sat问题。这里只要考虑选哪些人就可以。
如果a家的人认识b家的猫,那么如果选择了a家的人就必须选择b家的人。
利用这个条件建立一个图,然后找到所有最强联通分量。
如果联通分量只有1个,说明没有方案,如果有多个联通分量,
那么随便拿一个分量来作为人的选择,剩下的都选择猫即可,题解中是拿第1个。
AC代码
#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
#include <stack>
#include <vector>
#include <map>
#include <algorithm>
#include <assert.h>
using namespace std;
const int N = 6e6 +10;
const int E = 6e6+10;
// 边属性
class Edge {
public:
int toVertex;
int nextEdge;
};
// 点属性
class Node {
public:
int head;
int indu;
};
class Graph {
public:
Edge edges[E];
Node nodes[N];
int usedEdge=0;
Graph() {
usedEdge = 0;
}
void initEdge(int n) {
for(int i=0;i<=n;++i) {
nodes[i].head=-1;
nodes[i].indu = 0;
}
usedEdge = 0;
}
void addEdge(int a, int b) {
if(a==b) return;
edges[usedEdge].nextEdge = nodes[a].head;
nodes[a].head = usedEdge;
edges[usedEdge].toVertex = b;
nodes[b].indu++;
usedEdge++;
// cout<<"add edge: "<<a<<","<<b<<endl;
}
int dfn[N], low[N];
stack<int> st;
int deep, sum;
int color[N];
void initTarjan(int n) {
deep = 0;
sum=0;
memset(dfn, 0,sizeof(int)*n);
memset(low, 0,sizeof(int)*n);
memset(color, 0,sizeof(int)*n);
}
void tarjan(int u) {
dfn[u] = ++deep;
low[u] = deep;
st.push(u);
for(int i=nodes[u].head;i>=0;i = edges[i].nextEdge) {
int v = edges[i].toVertex;
if(!dfn[v]) {
tarjan(v);
low[u] = min(low[u], low[v]);
} else if(!color[v]) {
low[u] = min(low[u], dfn[v]);
}
}
if(dfn[u]==low[u]) {
color[u] = ++sum;
while(st.top()!=u) {
int v = st.top();
st.pop();
color[v]=sum;
}
st.pop();
}
}
map<int, int> loc;
bool topo(int n, bool deb) {
queue<int>qu;
for(int i=1;i<=n;++i) {
if(nodes[i].indu==0) {
qu.push(i);
}
}
int l=0;
while(!qu.empty()) {
int f = qu.front();
loc[f]=++l;
qu.pop();
for(int i=nodes[f].head;i>=0;i=edges[i].nextEdge) {
int v = edges[i].toVertex;
nodes[v].indu--;
if(nodes[v].indu==0) qu.push(v);
}
}
if(deb) cout<<l<<endl;
return l==n;
}
};
Graph og;
// false not swap
void either(int i, bool si, int j, bool sj) {
og.addEdge(i*2+(si^1), 2*j+sj);
og.addEdge(j*2+(sj^1), 2*i+si);
}
void must(int i, bool sel) {
og.addEdge(i*2+(sel^1), i*2+sel);
}
void solve() {
int n, m;
scanf("%d%d", &n, &m);
og.initEdge(n+10);
for(int i=0;i<m;++i) {
int a, b;
scanf("%d%d", &a, &b);
a--, --b;
og.addEdge(a, b);
}
og.initTarjan(n+10);
for(int i=0;i<n;++i) {
if(!og.dfn[i])og.tarjan(i);
}
if(og.sum<=1){
puts("No");
return;
}
vector<int> resident;
vector<int> cats;
for(int i=0;i<n;++i) {
if(og.color[i]==1){
resident.push_back(i);
}else {
cats.push_back(i);
}
}
puts("Yes");
printf("%d %d\n", resident.size(), cats.size());
for(int i=0;i<resident.size();++i){
if(i)putchar(' ');
printf("%d", resident[i]+1);
}
puts("");
for(int i=0;i<cats.size();++i){
if(i)putchar(' ');
printf("%d", cats[i]+1);
}
puts("");
}
int main() {
int t;
scanf("%d", &t);
while(t--) {
solve();
}
return 0;
}
/*
3
1 2 1
3 3 2
1
1 2 3
4
1 2 2 1
3 4 3 4
4
3 4 3 4
1 2 2 1
10
1 2 1 4 5 6 7 8 9 9
3 3 2 4 5 6 7 8 9 10
*/
本人码农,希望通过自己的分享,让大家更容易学懂计算机知识。