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
*/