题目链接:https://vjudge.net/problem/URAL-1099

1099. Work Scheduling

Time limit: 0.5 second
Memory limit: 64 MB
There is a certain amount of night guards that are available to protect the local junkyard from possible junk robberies. These guards need to be scheduled in pairs so that each pair guards in a different night. The junkyard CEO ordered you to write a program which given the guards characteristics determines the maximum amount of scheduled guards (the rest will be fired). Please note that each guard can be scheduled with only one of his colleagues and no guard can work alone.

Input

The first line of the input contains one number N ≤ 222 which is a number of night guards. Unlimited number of lines consisting of unordered pairs (ij) follow, each such pair means that guard #i and guard #j can work together, because it is possible to find uniforms that suit both of them (The junkyard uses different parts of uniforms for different guards i.e. helmets, pants, jackets. It is impossible to put small helmet on a guard with a big head or big shoes on guard with small feet). The input ends with Eof.

Output

You should output one possible optimal assignment. On the first line of the output write the even number C, the amount of scheduled guards. Then output C/2 lines, each containing 2 integers (ij) that denote that i and j will work together.

Sample

input output
3
1 2
2 3
1 3
2
1 2

题解:

一般图匹配带花树的模板题。还是看不太懂,以后有时间再看看。

有关怎么找到奇环:

其中可以把最右边两个点看成是找到奇环时的两个点,其中root为他们的LCA。

疑问1:什么要把花上的边的方向取反?

疑问2:为什么在找奇环时要特判 v==start ?

代码如下:

 #include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <sstream>
#include <algorithm>
using namespace std;
const int INF = 2e9;
const int MOD = 1e9+;
const int MAXM = +;
const int MAXN = 2e3+; int N;
bool graph[MAXN][MAXN];
int match[MAXN];
bool inque[MAXN], inpath[MAXN], inblos[MAXN];
queue<int>q;
int start, finish;
int newbase, fa[MAXN], base[MAXN]; int FindCommonAncester(int u, int v) //仅仅是找LCA,并不修改任何值
{
memset(inpath, false, sizeof(inpath));
while(true)
{
u = base[u];
inpath[u] = true;
if(u==start) break;
u = fa[match[u]];
}
while(true)
{
v = base[v];
if(inpath[v]) break;
v = fa[match[v]];
}
return v;
} void ResetTrace(int u) //把fa的方向取反
{
int v;
while(base[u]!=newbase) //匹配边、非匹配边交替出现
{
v = match[u]; //u--match[u]匹配边
inblos[base[u]] = inblos[base[v]] = true;
u = fa[v]; //v--fa[v]非匹配边
if(base[u]!=newbase) fa[u] = v;
}
} void BloosomContract(int u, int v)
{
newbase = FindCommonAncester(u, v);
memset(inblos, false, sizeof(inblos));
ResetTrace(u); //把u到LCA上的边取反
ResetTrace(v); //把v到LCA上的边取反
if(base[u]!=newbase) fa[u] = v; //看不懂
if(base[v]!=newbase) fa[v] = u; for(int tu = ; tu<=N; tu++)
if(inblos[base[tu]])
{
base[tu] = newbase; //设置它属于的集合
if(!inque[tu]) q.push(tu); //在花中的点加入队列,因为与花中点相连的点还可以找增广路
}
} void FindAugmentingPath()
{
memset(inque, false, sizeof(inque));
memset(fa, , sizeof(fa));
for(int i = ; i<=N; i++)
base[i] = i;
while(!q.empty()) q.pop();
q.push(start);
finish = ; while(!q.empty())
{
int u = q.front(); q.pop(); for(int v = ; v<=N; v++) //fa[u]--u是匹配边, u--v是未匹配边。
if(graph[u][v] && base[u]!=base[v] && match[u]!=v )
{
//为什么要特判 v==start ?
if( (v==start) || (match[v]> && fa[match[v]]>)) //找到奇环。
BloosomContract(u, v);
else if(fa[v]==) //v点在这次找增广路时没有被访问
{
fa[v] = u;
if(match[v]>) //如果已经匹配了,则加入他的匹配点,继续找增广路。
q.push(match[v]);
else //如果没有匹配,则找到了增广路。
{
finish = v;
return;
}
}
}
}
} void AugmentPath()
{
int u, v, w;
u = finish;
while(u>) //沿着增广路往回走,把匹配边和非匹配边取反
{
v = fa[u];
w = match[v];
match[v] = u;
match[u] = v;
u = w;
}
} void Edmonds()
{
memset(match, , sizeof(match));
for(int u = ; u<=N; u++)
if(match[u]==)
{
start = u;
FindAugmentingPath();
if(finish>) AugmentPath();
}
} int main()
{
scanf("%d", &N);
memset(graph, false, sizeof(graph));
int u, v;
while(scanf("%d%d", &u, &v)!=EOF)
graph[u][v] = graph[v][u] = true; Edmonds();
int sum = ;
for(int u = ; u<=N; u++)
if(match[u]>) sum++;
printf("%d\n", sum);
for(int u = ; u<=N; u++)
if(u<match[u])
printf("%d %d\n", u, match[u]); return ;
}

URAL1099 Work Scheduling —— 一般图匹配带花树的更多相关文章

  1. URAL 1099. Work Scheduling (一般图匹配带花树)

    1099. Work Scheduling Time limit: 0.5 secondMemory limit: 64 MB There is certain amount of night gua ...

  2. kuangbin带你飞 匹配问题 二分匹配 + 二分图多重匹配 + 二分图最大权匹配 + 一般图匹配带花树

    二分匹配:二分图的一些性质 二分图又称作二部图,是图论中的一种特殊模型. 设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集(A,B),并且图中的每条边(i,j)所关联的两个顶点i和j ...

  3. HDU 4687 Boke and Tsukkomi (一般图匹配带花树)

    Boke and Tsukkomi Time Limit: 3000/3000 MS (Java/Others)    Memory Limit: 102400/102400 K (Java/Othe ...

  4. URAL1099. Work Scheduling(一般图匹配带花树开花算法)

    1099. Work Scheduling Time limit: 0.5 second Memory limit: 64 MB There is certain amount of night gu ...

  5. HDU 4687 Boke and Tsukkomi 一般图匹配,带花树,思路,输出注意空行 难度:4

    http://acm.hdu.edu.cn/showproblem.php?pid=4687 此题求哪些边在任何一般图极大匹配中都无用,对于任意一条边i,设i的两个端点分别为si,ti, 则任意一个极 ...

  6. HDOJ 4687 Boke and Tsukkomi 一般图最大匹配带花树+暴力

    一般图最大匹配带花树+暴力: 先算最大匹配 C1 在枚举每一条边,去掉和这条边两个端点有关的边.....再跑Edmonds得到匹配C2 假设C2+2==C1则这条边再某个最大匹配中 Boke and ...

  7. ZOJ 3316 Game 一般图最大匹配带花树

    一般图最大匹配带花树: 建图后,计算最大匹配数. 假设有一个联通块不是完美匹配,先手就能够走那个没被匹配到的点.后手不论怎么走,都必定走到一个被匹配的点上.先手就能够顺着这个交错路走下去,最后一定是后 ...

  8. 【learning】一般图最大匹配——带花树

    问题描述 ​ 对于一个图\(G(V,E)\),当点对集\(S\)满足任意\((u,v)\in S\),均有\(u,v\in V,(u,v)\in E\),且\(S\)中没有点重复出现,我们称\(S\) ...

  9. UOJ #79 一般图最大匹配 带花树

    http://uoj.ac/problem/79 一般图和二分图的区别就是有奇环,带花树是在匈牙利算法的基础上对奇环进行缩点操作,复杂度似乎是O(mn)和匈牙利一样. 具体操作是一个一个点做类似匈牙利 ...

随机推荐

  1. IDEA+Tomcat热部署自动编译

    https://www.cnblogs.com/1024zy/p/6344000.html 之前太傻瓜了,一直以为用了IDEA改了类或者js的时候全都要手动构建发布,其实不用,IDEA这么好的工具怎么 ...

  2. 查看java进程中哪个线程在消耗系统资源

    1 top -p $pid -H  加上-H这个参数后,会列出有哪些线程.这样就可以看到哪个线程id最消耗系统资源了.看到的线程id是10进制的数字. 2 jstack $pid 可以打印出制定jav ...

  3. [luoguP2982][USACO10FEB]慢下来Slowing down(dfs序 + 线段树)

    传送门 这个题显然可以用树链剖分做. 然而线段树也能做. 每个点都对它的子树有贡献,所以先求一边 dfs序,然后直接在 dfs序 中搞 线段树 就行. ——代码 #include <cstdio ...

  4. 【dp】D. Caesar's Legions

    https://www.bnuoj.com/v3/contest_show.php?cid=9146#problem/D [题意]给定n1个A,n2个B,排成一排,要求A最多能连续k1个紧挨着,B最多 ...

  5. 【POJ2406】Power Strings(KMP,后缀数组)

    题意: n<=1000000,cas较大 思路:这是一道论文题 后缀数组已弃疗,强行需要DC3构造,懒得(不会)写 ..]of longint; n,m,i,j,len,ans,st:longi ...

  6. 【Ural1297】Palindrome(后缀数组)

    题意:求一个字符串的最长回文子串 n<=1000 思路:这是一道论文题 需要注意的细节: 1.奇偶分类 2.中间的分割符与最后的附加字母都是最小值,但两者不能相同,否则height可能会出现问题 ...

  7. 《effective C++》:条款37——绝不重新定义继承而来的缺省参数值

    引子: 阿里的一道题: #include <IOSTREAM> using namespace std; class A{ public: ) { cout<<"a~ ...

  8. Speculative store buffer

    A speculative store buffer is speculatively updated in response to speculative store memory operatio ...

  9. CSS属性操作二

    9.float属性 基本浮动规则 先来了解一下block元素和inline元素在文档流中的排列方式. block元素通常被现实为独立的一块,独占一行,多个block元素会各自新起一行,默认block元 ...

  10. POJ 2749 2SAT判定+二分

    题意:图上n个点,使每个点都与俩个中转点的其中一个相连(二选一,典型2-sat),并使任意两点最大 距离最小(最大最小,2分答案),有些点相互hata,不能选同一个中转点,有些点相互LOVE,必需选相 ...