CF Round 594 D. Catowice City

有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;
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值