R - Work scheduling

Time Limit:500MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u

Description

There is certain amount of night guards that are available to protect the local junkyard from possible junk robberies. These guards need to scheduled in pairs, so that each pair guards at 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 the amount 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

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

就是有n个人,之后给出若干个关系,之后求最大可以保留多少对关系,要求可以删除若干个人

下面两个都是模板,两个模板都是可以套用的·1

1

#include<stdio.h>
#include<string.h>
#include<string.h>
#include<iostream>
#include<queue>
#include<algorithm>
using namespace std;
const int MAXN = ;
int N; //点的个数,点的编号从1到N
bool Graph[MAXN][MAXN];
int Match[MAXN];
bool InQueue[MAXN],InPath[MAXN],InBlossom[MAXN];
int Head,Tail;
int Queue[MAXN];
int Start,Finish;
int NewBase;
int Father[MAXN],Base[MAXN];
int Count;//匹配数,匹配对数是Count/2
void CreateGraph()
{
int u,v;
memset(Graph,false,sizeof(Graph));
scanf("%d",&N);
while(scanf("%d%d",&u,&v) == )
{
Graph[u][v] = Graph[v][u] = true;
}
}
void Push(int u)
{
Queue[Tail] = u;
Tail++;
InQueue[u] = true;
}
int Pop()
{
int res = Queue[Head];
Head++;
return res;
}
int FindCommonAncestor(int u,int v)
{
memset(InPath,false,sizeof(InPath));
while(true)
{
u = Base[u];
InPath[u] = true;
if(u == Start) break;
u = Father[Match[u]];
}
while(true)
{
v = Base[v];
if(InPath[v])break;
v = Father[Match[v]];
}
return v;
}
void ResetTrace(int u)
{
int v;
while(Base[u] != NewBase)
{
v = Match[u];
InBlossom[Base[u]] = InBlossom[Base[v]] = true;
u = Father[v];
if(Base[u] != NewBase) Father[u] = v;
}
}
void BloosomContract(int u,int v)
{
NewBase = FindCommonAncestor(u,v);
memset(InBlossom,false,sizeof(InBlossom));
ResetTrace(u);
ResetTrace(v);
if(Base[u] != NewBase) Father[u] = v;
if(Base[v] != NewBase) Father[v] = u;
for(int tu = ; tu <= N; tu++)
if(InBlossom[Base[tu]])
{
Base[tu] = NewBase;
if(!InQueue[tu]) Push(tu);
}
}
void FindAugmentingPath()
{
memset(InQueue,false,sizeof(InQueue));
memset(Father,,sizeof(Father));
for(int i = ; i <= N; i++)
Base[i] = i;
Head = Tail = ;
Push(Start);
Finish = ;
while(Head < Tail)
{
int u = Pop();
for(int v = ; v <= N; v++)
if(Graph[u][v] && (Base[u] != Base[v]) && (Match[u] != v))
{
if((v == Start) || ((Match[v] > ) && Father[Match[v]] > ))
BloosomContract(u,v);
else if(Father[v] == )
{
Father[v] = u;
if(Match[v] > )
Push(Match[v]);
else
{
Finish = v;
return;
}
}
}
}
}
void AugmentPath()
{
int u,v,w;
u = Finish;
while(u > )
{
v = Father[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();
}
}
void PrintMatch()
{
Count = ;
for(int u = ; u <= N; u++)
if(Match[u] > )
Count++;
printf("%d\n",Count);
for(int u = ; u <= N; u++)
if(u < Match[u])
printf("%d %d\n",u,Match[u]);
}
int main()
{
CreateGraph();//建图
Edmonds();//进行匹配
PrintMatch();//输出匹配数和匹配
return ;
}

(2)

    #include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int N = ;
// 并查集维护
int belong[N];
int findb(int x) {
return belong[x] == x ? x : belong[x] = findb(belong[x]);
}
void unit(int a, int b) {
a = findb(a);
b = findb(b);
if (a != b) belong[a] = b;
} int n, match[N];
vector<int> e[N];
int Q[N], rear;
int next[N], mark[N], vis[N];
// 朴素算法求某阶段中搜索树上两点x, y的最近公共祖先r
int LCA(int x, int y) {
static int t = ; t++;
while (true) {
if (x != -) {
x = findb(x); // 点要对应到对应的花上去
if (vis[x] == t)
return x;
vis[x] = t;
if (match[x] != -)
x = next[match[x]];
else x = -;
}
swap(x, y);
}
} void group(int a, int p) {
while (a != p) {
int b = match[a], c = next[b]; // next数组是用来标记花朵中的路径的,综合match数组来用,实际上形成了
// 双向链表,如(x, y)是匹配的,next[x]和next[y]就可以指两个方向了。
if (findb(c) != p) next[c] = b; // 奇环中的点都有机会向环外找到匹配,所以都要标记成S型点加到队列中去,
// 因环内的匹配数已饱和,因此这些点最多只允许匹配成功一个点,在aug中
// 每次匹配到一个点就break终止了当前阶段的搜索,并且下阶段的标记是重
// 新来过的,这样做就是为了保证这一点。
if (mark[b] == ) mark[Q[rear++] = b] = ;
if (mark[c] == ) mark[Q[rear++] = c] = ; unit(a, b); unit(b, c);
a = c;
}
} // 增广
void aug(int s) {
for (int i = ; i < n; i++) // 每个阶段都要重新标记
next[i] = -, belong[i] = i, mark[i] = , vis[i] = -;
mark[s] = ;
Q[] = s; rear = ;
for (int front = ; match[s] == - && front < rear; front++) {
int x = Q[front]; // 队列Q中的点都是S型的
for (int i = ; i < (int)e[x].size(); i++) {
int y = e[x][i];
if (match[x] == y) continue; // x与y已匹配,忽略
if (findb(x) == findb(y)) continue; // x与y同在一朵花,忽略
if (mark[y] == ) continue; // y是T型点,忽略
if (mark[y] == ) { // y是S型点,奇环缩点
int r = LCA(x, y); // r为从i和j到s的路径上的第一个公共节点
if (findb(x) != r) next[x] = y; // r和x不在同一个花朵,next标记花朵内路径
if (findb(y) != r) next[y] = x; // r和y不在同一个花朵,next标记花朵内路径 // 将整个r -- x - y --- r的奇环缩成点,r作为这个环的标记节点,相当于论文中的超级节点
group(x, r); // 缩路径r --- x为点
group(y, r); // 缩路径r --- y为点
}
else if (match[y] == -) { // y自由,可以增广,R12规则处理
next[y] = x;
for (int u = y; u != -; ) { // 交叉链取反
int v = next[u];
int mv = match[v];
match[v] = u, match[u] = v;
u = mv;
}
break; // 搜索成功,退出循环将进入下一阶段
}
else { // 当前搜索的交叉链+y+match[y]形成新的交叉链,将match[y]加入队列作为待搜节点
next[y] = x;
mark[Q[rear++] = match[y]] = ; // match[y]也是S型的
mark[y] = ; // y标记成T型
}
}
}
} bool g[N][N];
int main() {
scanf("%d", &n);
for (int i = ; i < n; i++)
for (int j = ; j < n; j++) g[i][j] = false; // 建图,双向边
int x, y; while (scanf("%d%d", &x, &y) != EOF) {
x--, y--;
if (x != y && !g[x][y])
e[x].push_back(y), e[y].push_back(x);
g[x][y] = g[y][x] = true;
} // 增广匹配
for (int i = ; i < n; i++) match[i] = -;
for (int i = ; i < n; i++) if (match[i] == -) aug(i); // 输出答案
int tot = ;
for (int i = ; i < n; i++) if (match[i] != -) tot++;
printf("%d\n", tot);
for (int i = ; i < n; i++) if (match[i] > i)
printf("%d %d\n", i + , match[i] + );
return ;
}

URAL 1099 Work scheduling 一般图的最大匹配 带花树算法(模板)的更多相关文章

  1. URAL 1099 Work Scheduling (一般图最大匹配) 模板题【带花树】

    <题目链接> <转载于 >>>  > 题目大意: 给出n个士兵,再给出多组士兵之间两两可以匹配的关系.已知某个士兵最多只能与一个士兵匹配.求最多能够有多少对匹 ...

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

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

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

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

  4. 【模板】一般图最大匹配(带花树算法)/洛谷P6113

    题目链接 https://www.luogu.com.cn/problem/P6113 题目大意 给定一个 \(n\) 个点 \(m\) 条边的无向图,求该图的最大匹配. 题目解析 二分图最大匹配,一 ...

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

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

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

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

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

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

  8. Ural1099 Work Scheduling 一般图的最大匹配

    Ural1099 给定无向图, 求最大匹配. 在寻找增广路的过程中,可能出现一个奇环,这时候把奇环收缩,成为一朵“花”,并在新图上继续增广. 为了记录匹配关系,需要在花中寻找路径,每一条增广路径都可以 ...

  9. Ural 1099 Work Scheduling

    http://acm.timus.ru/problem.aspx?space=1&num=1099 题意:有n个人,很多对合作关系,每个人只能和一个人合作,求最多能选出多少人. 一般图匹配 # ...

随机推荐

  1. Windows计算机重置TCP / IP

    传输控制协议 (TCP / IP)是Internet上使用的通信协议. 在Windows的早期版本中,TCP / IP是一个单独的可选组件,可以像其他任何协议一样删除或添加. 早期版本中,从Windo ...

  2. tsung基准测试方法、理解tsung.xml配置文件、tsung统计报告简介

    网上搜集的资料,资料来源于:http://blog.sina.com.cn/ishouke 1.tsung基准测试方法 https://pan.baidu.com/s/1Ne3FYo8XyelnJy8 ...

  3. Windows系统下查看文件编码类型

    这是一个程序员的最基本的技能,原谅我到现在才去了解 以前只知道window操作系统下文件大部分默认编码是ANSI,中文版是GBK编码 如果想要查看或者修改文件编码的话有两种方式 一:用记事本打开文件, ...

  4. Vue.js-this详解

    this this 指向并不是在函数定义的时候确定的,而是在调用的时候确定的.换句话说,函数的调用方式(直接调用.方法调用.new调用.bind.call.apply.箭头函数)决定了 this 指向 ...

  5. 总结一下自己脑海里的JavaScript吧(一)--DOM模型

    今天是2019年6月25日,闲来无事,写一篇文章来看看自己脑袋里装了多少JavaScript知识! 这儿就第一章: 说起JavaScript,它是什么?后端脚本语言?前端编程语言?还是在网站浏览器上运 ...

  6. C++利用偏移量对文件操作

    对输入流操作:seekg()与tellg()对输出流操作:seekp()与tellp()下面以输入流函数为例介绍用法: seekg()是对输入文件定位,它有两个参数:第一个参数是偏移量,第二个参数是基 ...

  7. NSRegularExpression

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAu4AAAU2CAIAAABFtaRRAAAAAXNSR0IArs4c6QAAAe9pVFh0WE1MOm

  8. [].indexOf.call()学习

    今天看到闭包一道题,就是一个li列表,点击列表控制台输出对应的索引.这里考察了var的作用域问题和闭包对外部变量的引用问题,有几种解决方法. html: <ul> <li>te ...

  9. Python爬虫系列-PyQuery详解

    强大又灵活的网页解析库.如果你觉得正则写起来太麻烦,如果你觉得BeautifulSoup语法太难记,如果你熟悉jQuery的语法,那么PyQuery就是你的最佳选择. 安装 pip3 install ...

  10. Fedora 28 系统基础配置以及常用软件安装方式

    实验说明: 很多人说Linux很难用,很难上手,其实不然,倘若不玩游戏,其实很多发行版Linux都可以成为主力系统,就比如本章要讲的 Fedora 28.本章会从镜像来源.系统安装.基础配置和常用软件 ...