最小点权覆盖和最大点权独立集(定义与建模)
来源:互联网 发布:飞升真元锻体升级数据 编辑:程序博客网 时间:2024/05/21 18:31
原文网址:http://yzmduncan.iteye.com/blog/1149057
二分图最小点覆盖和最大独立集都可以转化为最大匹配求解。在这个基础上,把每个点赋予一个非负的权值,这两个问题就转化为:二分图最小点权覆盖和二分图最大点权独立集。
二分图最小点权覆盖
从x或者y集合中选取一些点,使这些点覆盖所有的边,并且选出来的点的权值尽可能小。
建模:
原二分图中的边(u,v)替换为容量为INF的有向边(u,v),设立源点s和汇点t,将s和x集合中的点相连,容量为该点的权值;将y中的点同t相连,容量为该点的权值。在新图上求最大流,最大流量即为最小点权覆盖的权值和。
二分图最大点权独立集
在二分图中找到权值和最大的点集,使得它们之间两两没有边。其实它是最小点权覆盖的对偶问题。答案=总权值-最小点覆盖集。具体证明参考胡波涛的论文。
例:HDU1569
题意:一个m*n的棋盘,每个格子都有一个权值,从中取出某些数,使得任意两个数所在的格子没有公共边,并且所取去出的数和最大。求这个最大的值。
解:
将格子染色成二分图,显然是求二分图的最大点权独立集。将问题转化为二分图最小点权覆盖来求解,最终结果=总权和-最大流。
/* 最大点权独立集: 转化为最小点权覆盖问题,最大点权独立集=总权值-最小点权覆盖集 最小点权覆盖: 设立源点s和t,s连边到点i,容量为i点的权值;点j连边到t,容量为j点权值;原二分图中的边容量为INF,求最大流即为最小点权覆盖。 */ #include <iostream> #include <cstdio> #include <cstring> using namespace std; const int INF = 0x7fffffff; const int maxv = 2600; const int maxe = 1000000; int n,m; int g[55][55]; struct Edge { int v; int next; int flow; }; Edge e[maxe]; int head[maxv],edgeNum; int now[maxv],d[maxv],vh[maxv],pre[maxv],preh[maxv]; int start,end; void addEdge(int a,int b,int c) { e[edgeNum].v = b; e[edgeNum].flow = c; e[edgeNum].next = head[a]; head[a] = edgeNum++; e[edgeNum].v = a; e[edgeNum].flow = 0; e[edgeNum].next = head[b]; head[b] = edgeNum++; } void Init() { edgeNum = 0; memset(head,-1,sizeof(head)); memset(d,0,sizeof(d)); } int sap(int s,int t,int n) //源点,汇点,结点总数 { int i,x,y; int f,ans = 0; for(i = 0; i < n; i++) now[i] = head[i]; vh[0] = n; x = s; while(d[s] < n) { for(i = now[x]; i != -1; i = e[i].next) if(e[i].flow > 0 && d[y=e[i].v] + 1 == d[x]) break; if(i != -1) { now[x] = preh[y] = i; pre[y] = x; if((x=y) == t) { for(f = INF,i=t; i != s; i = pre[i]) if(e[preh[i]].flow < f) f = e[preh[i]].flow; ans += f; do { e[preh[x]].flow -= f; e[preh[x]^1].flow += f; x = pre[x]; }while(x!=s); } } else { if(!--vh[d[x]]) break; d[x] = n; for(i=now[x]=head[x]; i != -1; i = e[i].next) { if(e[i].flow > 0 && d[x] > d[e[i].v] + 1) { now[x] = i; d[x] = d[e[i].v] + 1; } } ++vh[d[x]]; if(x != s) x = pre[x]; } } return ans; } void build() { int i,j; for(i = 1; i <= m; i++) { for(j = 1; j <= n; j++) { int t = (i-1)*n+j; if((i+j)%2) { addEdge(start,t,g[i][j]); if(i>1) addEdge(t,t-n,INF); if(i<m) addEdge(t,t+n,INF); if(j>1) addEdge(t,t-1,INF); if(j<n) addEdge(t,t+1,INF); } else addEdge(t,end,g[i][j]); } } } int main() { int i,j; int result; while(scanf("%d %d",&m,&n) != EOF) { result = 0; Init(); for(i = 1; i <= m; i++) { for(j = 1; j <= n; j++) { scanf("%d",&g[i][j]); result += g[i][j]; } } start = 0; end = n*m + 1; build(); printf("%d\n",result-sap(start,end,end+1)); } return 0; }
阅读全文
0 0
- 最小点权覆盖和最大点权独立集(定义与建模)
- 最小点权覆盖集&最大点权独立集
- 最小点权覆盖=最大点权独立集
- 二分图的最大点权独立集和最小点权覆盖集
- 网络流之--最小点权覆盖和最大点权独立集
- 网络流之--最小点权覆盖和最大点权独立集
- 网络流之最小点权覆盖和最大点权独立集学习
- 网络流之--最小点权覆盖和最大点权独立集
- HDU1569 方格取数(2)(最大点权独立集 + 最小点权覆盖集 = 总权和)
- 最小路径覆盖,最小点覆盖,最大独立点集
- 最小路径覆盖,最小点覆盖,最大独立点集
- 最大流=最小割=最小点权覆盖集=sum-最大点权独立集
- 最大流最小割(最大点权独立集)
- 二分图最大匹配,最小路径覆盖,最小点覆盖,最大独立集,最小边覆盖与建图方法
- 最小路径覆盖,最小点覆盖,最大独立点集,最小边覆盖
- 最小路劲覆盖 最小点覆盖 最大独立集
- 最小支配集、最小覆盖点、最大独立集
- 最小点覆盖,最小边覆盖,最大匹配,最小路径覆盖,最大独立集总结。
- 新手教程 Centos7安装二进制mysql 及遇到问题记录
- C#创建Excel(.xls和.xlsx)文件的三种方法
- 1192: 奖学金(结构体专题)
- hpuoj【1294】有序数组共有元素【水题】
- Tomcat8.5.20安装
- 最小点权覆盖和最大点权独立集(定义与建模)
- MATLAB 把m文件转化为C文件
- python中的控制条件、循环和跳出
- HDU 5938 && 2016CCPC杭州 F: Four Operations
- zcmu-1199
- Python的模块导入、包导入
- 各种排序及内省排序
- python中的列表、元祖、字典、集合
- hdu3333(线段树离散化离线处理)