zoukankan      html  css  js  c++  java
  • Gym

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

    题意

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

    [nleq300\ 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 << '
    ';
    		}
    	}
    	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
    ",p.size());
    	for(auto v:p)
    		printf("%d %d
    ",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
    */
    
  • 相关阅读:
    redis数据结构
    django内置密码原理
    生成图片验证码
    如何封装VUE的axios请求
    杭电1717小数化分数2
    杭电2504 又见GCD
    杭电 2136 Largest prime factor(最大素数因子的位置)
    Linux终端的一些快捷键命令
    杭电 1772 cake
    杭电ACM 1713 相遇周期
  • 原文地址:https://www.cnblogs.com/hznumqf/p/14026391.html
Copyright © 2011-2022 走看看