http://acm.hdu.edu.cn/showproblem.php?pid=4687

此题求哪些边在任何一般图极大匹配中都无用,对于任意一条边i,设i的两个端点分别为si,ti,

则任意一个极大匹配中都必然有si或ti至少一个点被匹配,当在图中去掉si,ti两个点时,匹配数会损失一个或两个.

如果损失两个,就说明在极大匹配中这两个点分别连接不同的边,于是边i是无用的

所以总体思路:一般图匹配求出最大匹配数cnt0,分别试着去掉每条边的端点,再次匹配,匹配数如果小于cnt0-1,则这条边无用,记录

ATTENTION:如果无用边数为0,仍然需要输出一个空行

带花树思想简介:

对于一对匹配点,设其中一个是S类型点,另外与之配对的是T点,如图

那么对于需要被增广的某个S类型点u,以及与它相连的点v有

1. v是T类型点
2. v还没有被匹配过

3. v是S类型点

三种情况

设match[i]是i的匹配点

对于第1)种情况,即使接上u,v,断开v和match[v],重整整个增广路也不会影响结果,忽略

对于第2)种情况,就像二分图一样,直接接上u,v并增广路取反

对于第3)种情况,有a. v不在当前增广路上 b.v在当前增广路上

对于3.a)情况,把v加入当前增广路,把两条增广路合并,或者说是把v的开花树并入u的

对于3.b)情况,设r为v,u的最近公共祖先,那么r-v-u-r形成了奇环,把奇环缩为一点,这个点就是开花算法的花,设新图为G',原图为G,可以证明G中有对应G的增广路,因为奇数环上任意一点都可以断开形成新增广路,所以都可以作为s点,不过一次只能断开一处

#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <assert.h>
using namespace std; const int MAXN = 45;
int n;//人数,start from 1
bool del[MAXN];//是否不可用
int e[MAXN][MAXN],sz[MAXN];//图
int match[MAXN];//对应边
bool inQue[MAXN],inPath[MAXN],inBlossom[MAXN];//状态
int que[MAXN],head,tail;//s点加入此队列更新
int start,finish;//增广路取反的开始点,结束点
int newFather;//开花算法
int nxt[MAXN],father[MAXN];//nxt 用于遍历开花树 father 标示所属花 void push(int u){
que[tail] = u;
tail++;
inQue[u] = true;
}
int pop(){
int res = que[head];
head++;
return res;
}
int findCommonAncestor(int u,int v){
memset(inPath,false,sizeof(inPath));
while(true){
u = father[u];
inPath[u] = true;
if(u == start) break;
u = nxt[match[u]];
}
while(true){
v = father[v];
if(inPath[v])break;
v = nxt[match[v]];
}
return v;
}
void resetTrace(int u){//连环
int v;
while(father[u] != newFather){
v = match[u];
inBlossom[father[u]] = inBlossom[father[v]] = true;
u = nxt[v];
if(father[u] != newFather) nxt[u] = v;
}
}
void bloosomContract(int u,int v){//连环
newFather = findCommonAncestor(u,v);
memset(inBlossom,false,sizeof(inBlossom));
resetTrace(u);
resetTrace(v);
if(father[u] != newFather) nxt[u] = v;
if(father[v] != newFather) nxt[v] = u;
for(int tu = 1; tu <= n; tu++)
if(inBlossom[father[tu]]){
father[tu] = newFather;
if(!inQue[tu]) push(tu);
}
}
void findAugmentingPath(){//增广主过程
memset(inQue,false,sizeof(inQue));
memset(nxt,0,sizeof(nxt));
for(int i = 1;i <= n;i++)father[i] = i;
head = tail = 1;
push(start);
finish = 0;
while(head < tail){
int u = pop();
assert(!del[u]);
for(int p = 0; p < sz[u]; p++){
int v=e[u][p];
if(!del[v] && (father[u] != father[v]) && (match[u] != v)){//v可用,u,v不在同一花中,u,v不是早已连接
if((v == start) || ((match[v] > 0) && nxt[match[v]] > 0))//奇数环,开花
bloosomContract(u,v);
else if(nxt[v] == 0){//合并开花树
nxt[v] = u;
if(match[v] > 0)
push(match[v]);
else{
finish = v;//找到配对点,成功
return;
}
}
}
}
}
}
void aug(){//增广路取反
int u,v,w;
u = finish;
while(u > 0){
v = nxt[u];
w = match[v];
match[v] = u;
match[u] = v;
u = w;
}
}
void Edmonds(){//增广算法
memset(match,0,sizeof(match));
for(int i = 1; i <= n; i++)
if(!del[i]&&match[i] == 0){
start = i;
findAugmentingPath();
if(finish > 0)aug();
}
}
int getMatch(){//统计结果
Edmonds();
int cnt = 0;
for(int i = 1; i <= n;i++)
if(match[i] > 0)
cnt++;
return cnt/2;
} bool g[MAXN][MAXN];
int from[MAXN*4],to[MAXN*4];
int heap[MAXN*4];
int main(){
int m;
while(scanf("%d%d",&n,&m)==2){
memset(g,false,sizeof(g));
memset(del,false,sizeof(del));
memset(sz,0,sizeof(sz));
for(int i = 0;i <m;i++){
scanf("%d%d",from+i,to+i);
int f=from[i],t=to[i];
if(!g[f][t]){
g[f][t]=g[t][f]=true;
e[f][sz[f]++]=t;
e[t][sz[t]++]=f;
}
}
int cnt0 = getMatch(); int ans=0;
for(int i = 0;i <m;i++){
int f=from[i],t=to[i];
del[f]=del[t]=true;
int cnt = getMatch();
if(cnt == cnt0-2){heap[ans++]=i+1;}
del[t]=del[f]=false;
}
printf("%d\n",ans);
for(int i=0;i<ans;i++){
printf("%d%c",heap[i],i==ans-1?'\n':' ');
}
if(ans==0)puts("");
}
return 0;
}

  

HDU 4687 Boke and Tsukkomi 一般图匹配,带花树,思路,输出注意空行 难度:4的更多相关文章

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

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

  2. HDU 4687 Boke and Tsukkomi (一般图最大匹配)【带花树】

    <题目链接> 题目大意: 给你n个点和m条边,每条边代表两点具有匹配关系,问你有多少对匹配是冗余的. 解题分析: 所谓不冗余,自然就是这对匹配关系处于最大匹配中,即该匹配关系有意义.那怎样 ...

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

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

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

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

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

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

  6. URAL1099 Work Scheduling —— 一般图匹配带花树

    题目链接:https://vjudge.net/problem/URAL-1099 1099. Work Scheduling Time limit: 0.5 secondMemory limit: ...

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

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

  8. hdu 4687 Boke and Tsukkomi

    Dancing link twice. Find the maximum combination numbers in the first time. Enumerate each node, dan ...

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

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

随机推荐

  1. 商铺项目(使用DES加密配置信息)

    package com.ouyan.o2o.util; import java.security.Key; import java.security.SecureRandom; import java ...

  2. mysql索引详解(转)

    什么是索引 索引用来快速地寻找那些具有特定值的记录,所有MySQL索引都以B-树的形式保存.如果没有索引,执行查询时MySQL必须从第一个记录开始扫描整个表的所有记录,直至找到符合要求的记录.表里面的 ...

  3. Openstack(十)部署nova服务(计算节点)

    在计算节点安装 10.1安装nova计算服务 # 阿里云源详见2.3配置 # yum install openstack-nova-compute 10.2配置nova计算服务 10.2.1配置nov ...

  4. Spark SQL的整体实现逻辑

    1.sql语句的模块解析 当我们写一个查询语句时,一般包含三个部分,select部分,from数据源部分,where限制条件部分,这三部分的内容在sql中有专门的名称: 当我们写sql时,如上图所示, ...

  5. Selenium IDE的一些操作

    1.运行速度过快时,可能出现找不到元素的情况,影响运行结果,将速度调慢慢一些,就可以运行成功. 如果为其他情况找不到元素,则需要另外找原因,有可能元素定位有问题,有可能无该元素. 2.导出录制的脚本为 ...

  6. 系统管理命令之who

    作为一名系统管理员,我们需要弄清楚在一个特定的时间点都有谁活跃在系统上.必须严密监视我们的服务器.但是,我们当然不可能一天24小时都盯着系统.在linux系统中,我们可以使用who命令查看登录者信息. ...

  7. ACM ICPC, JUST Collegiate Programming Contest (2018) Solution

    A:Zero Array 题意:两种操作, 1 p v  将第p个位置的值改成v  2  查询最少的操作数使得所有数都变为0  操作为可以从原序列中选一个非0的数使得所有非0的数减去它,并且所有数不能 ...

  8. Flask添加翻页功能(非sqlalchemy)

    最近做flask的项目,需要增加翻页的功能,网上找的教程都是结合sqlalchemy的,可是我用的不是sqlalchemy,肿木办呢? 以下是我的做法 一.前端 1.传递页码 前端我使用ajax提交表 ...

  9. mongoose 获取某个存在的collecion 里的数据

    在创建Schma 时指定对应的collection var db_url = 'mongodb://localhost:27017/test'; var db = mongoose.connect(d ...

  10. 前端面试题之 sum(2)(3) (链式调用,toString,柯里化,数组操作)

    写一个函数让下面两个输出结果相同:console.log(sum(2)(3));console.log(sum(2,3)); var sum = (function() { var list = [] ...