Gym - 101755D Transfer Window 二分图 打印路径

Gym - 101755D Transfer Window 二分图 打印路径

题意

给出\(n\)个球员,\(n\times n\)的矩阵表示\(a\)能否交换\(b\),现有\(k\)个球员\(a_1,a_2...a_k\),希望得到\(b_1,b_2...b_k\)。问是否存在交换方案,若有,按顺序输出交换方案。

\[n\leq300\\ k \leq n \]

分析

显然这是一个图论问题。考虑到最后只需要考虑两部分的点,我们试图转化为二分图模型。

对图求闭包转化为可达矩阵,如果最后匹配数为\(k\)说明存在交换方案。

考虑如何打印路径,枚举每个需要的球员,dfs他的match到他的路径即可,如果一个条路径是\(A->b->c->B->d->AA\)

其中大写字母表示目前是现有球员,两个大写字母表示是需要的球员。

那么我们只需要\(B->d,d->AA\),\(A->b,b->c,c->B\)即可,基于此写一个dfs函数

此题思路大致就是这样,但还要注意一些细节处理

代码

int f[maxn][maxn];
vector<int> E[maxn];
vector<int> e[maxn];
bool vis[maxn];
bool vv[maxn];
int match[maxn];
int is_a[maxn],is_aaa[maxn];
int is_b[maxn],is_bbb[maxn];
vector<int> pa,pb;
vector<pii> p;
vector<pii> tmp;
int n,m;
int k;

bool dfs(int u){
	for(auto v:E[u]){
		if(vis[v]) continue;
		vis[v] = 1;
		if(!match[v] || dfs(match[v])){
			match[v] = u;
			match[u] = v;
			return true;
		}
	}
	return false;
}

int Match(){
	int res = 0;
	for(auto i:pa){
		memset(vis,0,sizeof vis);
		if(dfs(i)) res++;
	}
	return res;
}


int dfs(int s,int t){
	if(s == t) return 1;
	for(auto v:e[s]){
		if(!vv[v]){
			vv[v] = 1;
			if(dfs(v,t)){
				tmp.pb(make_pair(s,v));
				if(is_aaa[s]){
					while(!tmp.empty()){
						p.pb(tmp.back());
						tmp.pop_back();
					}
				}
				return 1;
			}
		}
	}
	return 0;
}



int main(){
	n = readint();
	k = readint();
	for(int i = 1;i <= k;i++)
		pa.push_back(readint()),is_a[pa.back()] = 1,is_aaa[pa.back()] = 1;
	for(int i = 1;i <= k;i++)
		pb.push_back(readint()),is_b[pb.back()] = 1,is_bbb[pb.back()] = 1;
	for(int i = 1;i <= n;i++){
		if(is_a[i] && is_b[i]) {
			is_a[i] = is_b[i] = 0;
			k--;
		}
	}
	pa.clear();
	pb.clear();
	for(int i = 1;i <= n;i++){
		if(is_a[i]) pa.pb(i);
		if(is_b[i]) pb.pb(i);
	}
	for(int i = 1;i <= n;i++)
		for(int j = 1;j <= n;j++)
			{
				scanf("%1d",&f[i][j]);
				if(f[i][j] && i != j) 
					e[i].pb(j);
			}
	for(int k = 1;k <= n;k++)
		for(int i = 1;i <= n;i++)
			for(int j = 1;j <= n;j++)
				f[i][j] |= f[i][k] & f[k][j];
	for(auto v:pa){
		for(auto u:pb){
			if(f[v][u]) E[v].pb(u);
			if(f[u][v]) E[u].pb(v);
			//cout << v << ' ' << u << '\n';
		}
	}
	if(Match() != k) {
		puts("NO");
		return 0;
	}
	for(int i = 1;i <= n;i++){
		if(is_bbb[i]){
			memset(vv,0,sizeof vv);
			int from = match[i];
			int to = i;
			if(is_aaa[to]) continue;
			vv[from] = 1;
			dfs(from,to);
			is_aaa[from] = 0;
			is_aaa[to] = 1;
		} 
	}
	puts("YES");
	printf("%d\n",p.size());
	for(auto v:p)
		printf("%d %d\n",v.fi,v.se);
	
}

/*
5 3
1 2 3
2 3 4
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
1 1 1 1 1
*/
上一篇:Gym-102411K


下一篇:CVE-2020-0796永恒之黑复现POC EXP以及修复方案