博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
URAL 1099 Work scheduling 一般图的最大匹配 带花树算法(模板)
阅读量:5055 次
发布时间:2019-06-12

本文共 8311 字,大约阅读时间需要 27 分钟。

R - Work scheduling
Time Limit:500MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u
Submit

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 (
i
j) 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 (
i
j) that denote that
i and
j will work together.

Sample Input

input output
31 22 31 3
21 2

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

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

1

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

(2)

#include 
#include
#include
#include
using namespace std; const int N = 250; // 并查集维护 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
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 = 0; t++; while (true) { if (x != -1) { x = findb(x); // 点要对应到对应的花上去 if (vis[x] == t) return x; vis[x] = t; if (match[x] != -1) x = next[match[x]]; else x = -1; } 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] == 2) mark[Q[rear++] = b] = 1; if (mark[c] == 2) mark[Q[rear++] = c] = 1; unit(a, b); unit(b, c); a = c; } } // 增广 void aug(int s) { for (int i = 0; i < n; i++) // 每个阶段都要重新标记 next[i] = -1, belong[i] = i, mark[i] = 0, vis[i] = -1; mark[s] = 1; Q[0] = s; rear = 1; for (int front = 0; match[s] == -1 && front < rear; front++) { int x = Q[front]; // 队列Q中的点都是S型的 for (int i = 0; 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] == 2) continue; // y是T型点,忽略 if (mark[y] == 1) { // 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] == -1) { // y自由,可以增广,R12规则处理 next[y] = x; for (int u = y; u != -1; ) { // 交叉链取反 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]] = 1; // match[y]也是S型的 mark[y] = 2; // y标记成T型 } } } } bool g[N][N]; int main() { scanf("%d", &n); for (int i = 0; i < n; i++) for (int j = 0; 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 = 0; i < n; i++) match[i] = -1; for (int i = 0; i < n; i++) if (match[i] == -1) aug(i); // 输出答案 int tot = 0; for (int i = 0; i < n; i++) if (match[i] != -1) tot++; printf("%d\n", tot); for (int i = 0; i < n; i++) if (match[i] > i) printf("%d %d\n", i + 1, match[i] + 1); return 0; }

 

转载于:https://www.cnblogs.com/13224ACMer/p/4844922.html

你可能感兴趣的文章
SQLServer 镜像功能完全实现
查看>>
Vue-详解设置路由导航的两种方法
查看>>
一个mysql主从复制的配置案例
查看>>
大数据学习系列(8)-- WordCount+Block+Split+Shuffle+Map+Reduce技术详解
查看>>
dvwa网络渗透测试环境的搭建
查看>>
Win8 安装VS2012 和 Sql Server失败问题
查看>>
过点(2,4)作一直线在第一象限与两轴围成三角形,问三角形面积的最小值?...
查看>>
java aes CBC的填充方式发现
查看>>
使用ionic cordova build android --release --prod命令打包报有如下错误及解决方法
查看>>
BZOJ 2338 HNOI2011 数矩形 计算几何
查看>>
关于页面<!DOCTYPE>声明
查看>>
【AS3代码】播放FLV视频流的三步骤!
查看>>
C++标准库vector使用(更新中...)
查看>>
cocos2d-x 2.2.6 之 .xml文件数据读取
查看>>
枚举的使用
查看>>
BZOJ 1531 二进制优化多重背包
查看>>
BZOJ 2324 (有上下界的)费用流
查看>>
python3基础06(随机数的使用)
查看>>
Zookeeper系列(二)特征及应用场景
查看>>
【HTTP】Fiddler(三)- Fiddler命令行和HTTP断点调试
查看>>