题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4687

  题意:给一个无向图,求所有的最大匹配的情况所不包含的边。。

  数据比较小,直接枚举边。先求一次最大匹配hig,然后依次枚举所有边,假设此边为一个匹配,那么删掉边的两个节点,然后再剩下的图中求最大匹配t,如果t<hig-1那么就是不包含的边了。关于一般图上的最大匹配算法,O(n^3)的Edmonds's matching algorithm,理解起来比较容易,但是写起来比较麻烦,收集了一个模板,by Amber。。。

 //STATUS:C++_AC_46MS_236KB
#include <functional>
#include <algorithm>
#include <iostream>
//#include <ext/rope>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <numeric>
#include <cstring>
#include <cassert>
#include <cstdio>
#include <string>
#include <vector>
#include <bitset>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <list>
#include <set>
//#include <map>
using namespace std;
//#pragma comment(linker,"/STACK:102400000,102400000")
//using namespace __gnu_cxx;
//define
#define pii pair<int,int>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI acos(-1.0)
//typedef
typedef __int64 LL;
typedef unsigned __int64 ULL;
//const
const int N=;
const int INF=0x3f3f3f3f;
const int MOD=,STA=;
const LL LNF=1LL<<;
const double EPS=1e-;
const double OO=1e15;
const int dx[]={-,,,};
const int dy[]={,,,-};
const int day[]={,,,,,,,,,,,,};
//Daily Use ...
inline int sign(double x){return (x>EPS)-(x<-EPS);}
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T lcm(T a,T b,T d){return a/d*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}
template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}
template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}
template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}
//End int a,b;
int n,m;
int head,tail,Start,Finish;
int link[N]; //表示哪个点匹配了哪个点
int Father[N]; //这个就是增广路的Father……但是用起来太精髓了
int Base[N]; //该点属于哪朵花
int Q[N];
bool mark[N];
bool map[N][N];
bool InBlossom[N];
bool in_Queue[N]; void BlossomContract(int x,int y)
{
fill(mark,mark+n+,false);
fill(InBlossom,InBlossom+n+,false);
#define pre Father[link[i]]
int lca,i;
for (i=x;i;i=pre) {i=Base[i]; mark[i]=true; }
for (i=y;i;i=pre) {i=Base[i]; if (mark[i]) {lca=i; break;} } //寻找lca之旅……一定要注意i=Base[i]
for (i=x;Base[i]!=lca;i=pre){
if (Base[pre]!=lca) Father[pre]=link[i]; //对于BFS树中的父边是匹配边的点,Father向后跳
InBlossom[Base[i]]=true;
InBlossom[Base[link[i]]]=true;
}
for (i=y;Base[i]!=lca;i=pre){
if (Base[pre]!=lca) Father[pre]=link[i]; //同理
InBlossom[Base[i]]=true;
InBlossom[Base[link[i]]]=true;
}
#undef pre
if (Base[x]!=lca) Father[x]=y; //注意不能从lca这个奇环的关键点跳回来
if (Base[y]!=lca) Father[y]=x;
for (i=;i<=n;i++){
if(i==a || i==b)continue;
if (InBlossom[Base[i]]){
Base[i]=lca;
if (!in_Queue[i]){
Q[++tail]=i;
in_Queue[i]=true; //要注意如果本来连向BFS树中父结点的边是非匹配边的点,可能是没有入队的
}
}
}
} void Change()
{
int x,y,z;
z=Finish;
while (z){
y=Father[z];
x=link[y];
link[y]=z;
link[z]=y;
z=x;
}
} void FindAugmentPath()
{
fill(Father,Father+n+,);
fill(in_Queue,in_Queue+n+,false);
for (int i=;i<=n;i++) Base[i]=i; //Init属于同一花朵
head=; tail=;
Q[]=Start; //当前节点进入队列
in_Queue[Start]=;
while (head!=tail){
int x=Q[++head];
for (int y=;y<=n;y++){
if(y==a || y==b)continue;
if (map[x][y] && Base[x]!=Base[y] && link[x]!=y){ //无意义的边
if ( Start==y || link[y] && Father[link[y]] ) //精髓地用Father表示该点是否
BlossomContract(x,y);
else if (!Father[y]){
Father[y]=x;
if (link[y]){
Q[++tail]=link[y];
in_Queue[link[y]]=true;
}
else{
Finish=y;
Change();
return;
}
}
}
}
}
} int Edmonds()
{
int i,cnt=;
memset(link,,sizeof(link));
memset(Father,,sizeof(Father));
for (Start=;Start<=n;Start++){
if(Start==a || Start==b)continue;
if (link[Start]==)
FindAugmentPath(); //如果点没有匹配,那么找BFS增广路
} for(i=;i<=n;i++)
if(link[i])cnt++;
return cnt;
} int e[][],ans[]; int main(){
// freopen("in.txt","r",stdin);
int i,j,hig,cnt;
while(~scanf("%d%d",&n,&m))
{
mem(map,);
for(i=;i<m;i++){
scanf("%d%d",&e[i][],&e[i][]);
map[e[i][]][e[i][]]=map[e[i][]][e[i][]]=true;
} a=b=-;
hig=Edmonds();
cnt=;
for(i=;i<m;i++){
a=e[i][],b=e[i][];
int t=Edmonds();
if(t<hig-)ans[cnt++]=i+;
} printf("%d\n",cnt);
if(cnt){
printf("%d",ans[]);
for(i=;i<cnt;i++)
printf(" %d",ans[i]);
}
putchar('\n');
}
return ;
}

HDU-4687 Boke and Tsukkomi 带花树,枚举的更多相关文章

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

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

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

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

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

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

  4. hdu 4687 Boke and Tsukkomi

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

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

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

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

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

  7. Hdu4687 Boke and Tsukkomi

    Boke and Tsukkomi                                                                               Time ...

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

    一般图最大匹配--带花树 问题 ​ 给定一个图,求该图的最大匹配.即找到最多的边,使得每个点至多属于一条边. ​ 这个问题的退化版本就是二分图最大匹配. ​ 由于二分图中不存在奇环,偶环对最大匹配并无 ...

  9. [转]带花树,Edmonds's matching algorithm,一般图最大匹配

    看了两篇博客,觉得写得不错,便收藏之.. 首先是第一篇,转自某Final牛 带花树……其实这个算法很容易理解,但是实现起来非常奇葩(至少对我而言). 除了wiki和amber的程序我找到的资料看着都不 ...

随机推荐

  1. Firefly Http通信简单介绍

    原地址:http://www.9miao.com/question-15-54042.html 首先创建firefly工程,firefly-admin.py createproject httptes ...

  2. IsBadReadPtr|IsBadWritePtr调试崩溃

    遇到一未找到必然出现条件的崩溃,不知道什么时候能触发崩溃,崩溃dump显示,试图访问了非法的内存或者写入了非法的内存 此时如下两个函数就比较有用了: BOOL WINAPI IsBadReadPtr( ...

  3. Binding to the Most Recent Visual Studio Libraries--说的很详细,很清楚

    Every version of Visual Studio comes with certain versions of the Microsoft libraries, such as the C ...

  4. 使用Data Annotations进行手动数据验证

    Data Annotations是在Asp.Net中用于表单验证的 它通过Attribute直接标记字段的有效性,简单且直观.在非Asp.Net程序中(如控制台程序),我们也可以使用Data Anno ...

  5. Android应用启动画面

    原文地址: [Android]应用启动画面 - 空客的日志 - 网易博客 http://blog.163.com/da7_1@126/blog/static/104072678201291921028 ...

  6. Google Code Style

    Google开源项目的代码遵循的规范,见这,C++, OC. PS: vim的配色编辑用户主目录下的.vimrc即可.

  7. POJ2506——Tiling

    Tiling Description In how many ways can you tile a 2xn rectangle by 2x1 or 2x2 tiles? Here is a samp ...

  8. JBoss7 局域网无法访问 解决方法

    JBoss7 局域网无法访问 解决方法 在standalone模式,修改/standalone/configuration/standalone.xml.如下 修改或新增一个interface. &l ...

  9. 数据库 MySQL Jdbc JDBC的六个固定步骤

    *0 案例:    a)在JavaScript中使用正则表达式,在JS中正则表达式的定界符是://     var regexp = /^[0-9]+$/;     if(regexp.test(nu ...

  10. CodeWars可以学习的

    http://www.codewars.com/kata/54ff3102c1bad923760001f3/solutions/csharp 判断给定的字符串有多少个a e i o u using S ...