有N个人和N只猫,每个人都认识一些猫(其中包括自己的猫)。要求选出j裁判和p只猫,使得j+p=N,且选出的人和猫都互相不认识。输出任意一种方案。
我不会2-sat
其实很简单,两排点,人向认识的猫连有向边,猫向自己的主人连有向边,那么如果只有一个强联通分量则无解,否则随便取一个强联通分量中的人作为裁判,其他人的猫作为选手。
2-sat是真的脑瘫,关于2-sat解决至少一只猫和一个人的问题,需要用到
a
o
r
b
=
c
a \ or \ b = c
a or b=c,这,2-sat不能做。
A C C o d e : \rm AC \ Code: AC Code:
#include<bits/stdc++.h>
#define maxn 2000006
#define pb push_back
using namespace std;
int n,m;
int info[maxn],Prev[maxn],to[maxn],cnt_e;
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }
int dfn[maxn],low[maxn],c[maxn],q[maxn],L,R,scc,tot;
void dfs(int u){
dfn[u] = low[u] = ++tot;q[R++] = u;
for(int i=info[u],v;i;i=Prev[i])
if(!dfn[v=to[i]]) dfs(v),low[u]=min(low[u],low[v]);
else if(!c[v]) low[u] = min(low[u] , dfn[v]);
if(low[u] == dfn[u]){
scc++;
for(int t = -1;t != u;)
c[t = q[--R]] = scc;
}
}
vector<int>a1,a2;
int main(){
int T;
for(scanf("%d",&T);T--;){
scanf("%d%d",&n,&m);
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);
if(u != v) Node(u,v+n);
}
for(int i=1;i<=n;i++) Node(i+n,i);
for(int i=1;i<=n;i++)
if(!dfn[i])
dfs(i);
if(scc==1) puts("No");
else{
puts("Yes");
a1.clear(),a2.clear();
for(int i=1;i<=n;i++){
if(c[i] == 1) a1.pb(i);
else a2.pb(i);
}
printf("%d %d\n",a1.size(),a2.size());
for(int i=0;i<a1.size();i++) printf("%d%c",a1[i]," \n"[i==a1.size()-1]);
for(int i=0;i<a2.size();i++) printf("%d%c",a2[i]," \n"[i==a2.size()-1]);
}
for(int i=1;i<=2*n;i++)
info[i] = dfn[i] = low[i] = c[i] = 0;
scc = tot = L = R = cnt_e = 0;
}
}