codeforces gym-101755 D-Transfer Window 二分图匹配、递归
2018-04-02 11:17
567 查看
题目
题目链接题意
告诉了n名球员的交换关系,你现在拥有k名球员,你想要其他k名球员(有的在自己队里)。输出一种交换方案。
题解
第一步、求闭包。
我们需要在原来的交换矩阵上跑可达闭包,即G[i][j]G[i][j]的含义是jj是否能通过ii的一些交换得到,例如用ii交换aa,再用aa交换bb,再用bb来交换jj。预处理闭包的时间复杂度是O(n3)O(n3)。第二步、建立二分图。
先预处理出将同时存在与现在队伍里,和目标队伍里的球员,这类球员不将其加入二分图中去。二分图的左半边是只出现在现在队伍里的球员,二分图的右边是只出现在目标队伍里的球员。
凡是现在队伍的球员aa能够换成目标队伍里的球员bb的,就在(a,b)(a,b)之间链接一条边。
然后跑一个二分图匹配。((a,b)(a,b)匹配的含义就是可以把我队的aa换成目标队伍里的bb,并且不影响其他任何球员的归属。)
第三步、无解判定。
当且仅当我队伍中所有加入二分图的球员都匹配上了,说明有解,其他情况无解。第四步、输出方案。
注意,大写字母代表这个球员当前属于我队。我们遍历二分图中所有的匹配(A,b)(A,b),然后从原矩阵任意找一条从aa到bb的路径,例如A−>c−>d−>E−>f−>bA−>c−>d−>E−>f−>b。
那么我们输出方案如下:E−>f,f−>b,A−>c,c−>d,d−>EE−>f,f−>b,A−>c,c−>d,d−>E
然后再把b设置为我队,把A设置为非我队。
这样输出方案保证了把 A 换成 b 的同时,其他的球员的归属没有发生改变。
输出方案的算法:从后往前依次找到属于当前位置的节点,并把后面的箭头依次输出即可。例如先找到了EE输出E−>f,f−>bE−>f,f−>b ,又找到了AA,输出A−>c,c−>d,d−>EA−>c,c−>d,d−>E。
第五步、细节。
如何寻找从AA到bb的一条路径呢。使用dfs方法,但要注意经过的点打上标记vis[i] = 1,但是,在返回的时候不要将标记取消!在返回的时候不要将标记取消!在返回的时候不要将标记取消!重要的话说三遍,因为我们只要找到一条路径就好了,如果在返回过程中将标记取消的话,时间复杂度会爆掉。
证明:不取消标记可以找到一条路径。
如果通过某条路径走到vv节点而未能从vv节点走到目标点的话,通过其他路径走到vv点也不会走到目标点,这是很显然的。因此,只要被访问过的点,而没有走到终点,我们就无需再次访问了。
代码
#include <string.h> #include <vector> #include <queue> #include <iostream> #include <cstdio> using namespace std; typedef std::vector<int>::iterator iterator_t; struct Edge { int from, to; }; #define max_nodes 307 std::vector<Edge> edges; std::vector<int> G[700]; int num_nodes; int num_edges; int num_left, num_right; int match[700]; bool check[700]; inline void insert(int lefti, int righti){ G[lefti].push_back(edges.size()); edges.push_back((Edge){lefti, num_left + righti}); G[num_left + righti].push_back(edges.size()); edges.push_back((Edge){num_left + righti, lefti}); } bool dfs(int u){ for(iterator_t i = G[u].begin(); i != G[u].end(); ++i){ int v = edges[*i].to; if(check[v]) continue; check[v] = true; if((match[v] == -1) || dfs(match[v])){ match[u] = v; match[v] = u; return true; } } return false; } int hungarian(void){ int ans = 0; memset(match, -1, sizeof(match)); for(int i = 0; i < num_left; i++){ if(match[i] != -1) continue; memset(check, 0, sizeof(bool) * num_nodes); if(dfs(i)) ans++; } return ans; } int MG2[max_nodes][max_nodes]; int n,k; int wanted[max_nodes]; int myteam[max_nodes]; int vis[max_nodes]; int vv[max_nodes]; typedef pair<int,int> pii; vector<pii> fans; vector<int> vG[max_nodes]; pii ps[max_nodes]; int pcnt = 0; int main(){ scanf("%d%d",&n,&k); for(int i = 0;i < k;++i){ int tmp; scanf("%d",&tmp); myteam[tmp] = 1; } for(int i = 0;i < k;++i){ int tmp; scanf("%d",&tmp); wanted[tmp] = 1; } for(int i = 1;i <= n;++i) for(int j = 1;j <= n;++j){ char c; scanf(" %c",&c); MG2[i][j] = c == '1'; if(c == '1') vG[i].push_back(j); } //floyd for(int k = 1;k <= n;++k) for(int i = 1;i <= n;++i) for(int j = 1;j <= n;++j) MG2[i][j] |= MG2[i][k]&MG2[k][j]; int cnt = k; for(int i = 1;i <= n;++i) if(myteam[i] && wanted[i]) vis[i] = 1,cnt--; num_nodes = 2*n; num_right = num_left = n; for(int i = 1;i <= n;++i) if(!vis[i] && myteam[i]) for(int j = 1;j <= n;++j) if(!vis[j] && wanted[j] && MG2[i][j]){ insert(i-1,j-1); } int ans = hungarian(); if(ans != cnt) return 0*puts("NO"); int dfs2(int,int); for(int i = 1;i <= n;++i){ if(wanted[i]){ memset(vv,0,sizeof(vv)); int from = match[i-1+n]+1; int to = i; if(myteam[to]) continue; vv[from] = 1 ; dfs2(from,to); //vv[from] = 0; myteam[from] = 0; myteam[to] = 1; } } puts("YES"); printf("%d\n",fans.size()); for(auto p : fans) printf("%d %d\n",p.first,p.second); return 0; } int dfs2(int s,int t){ if(s == t) return 1; for(auto i : vG[s]){ if(!vv[i]){ vv[i] = 1; int r = dfs2(i,t); //vv[i] = 0; if(r){ ps[pcnt++] = make_pair(s,i); if(myteam[s]){ while(pcnt--) fans.push_back(ps[pcnt]); pcnt = 0; } return 1; } } } return 0; }
相关文章推荐
- codeforces gym-101755 I-Guess the Tree 交互题、分治、树的直径
- Codeforces Gym 101190 NEERC 16 .L List of Primes(递归)
- Codeforces Gym 101173 F. Free Figurines (递归)
- CodeForces Gym 100735G 二分图匹配
- CodeForces Gym 100803A 模拟,贪心
- CodeForces Gym 100114C 打表
- codeforces GYM 101431E (状态压缩dp+博弈)
- codeforces Gym 100187J J. Deck Shuffling dfs
- Codeforces Gym 100825 F. Transportation Delegation (最大流)
- Codeforces Gym 100463E Spies 并查集
- UVA Live 7958 (Codeforces Gym 101201G) Maximum Islands 二分图染色+匹配
- Codeforces Gym 100889 B Backward and Forward
- codeforces GYM 100781A【树的直径】
- CodeForces Gym 100500A A. Poetry Challenge DFS
- Codeforces Gym 100231G Voracious Steve 记忆化搜索
- Codeforces Gym 100015G Guessing Game 差分约束
- Codeforces Gym 100342H Problem H. Hard Test 构造题,卡迪杰斯特拉
- Codeforces Gym 100286F Problem F. Fibonacci System 数位DP
- Codeforces Gym 100203D Different vectors 想法题 + Hash
- Codeforces Gym 100203I I - I WIN 网络流最大流