一般图带权多重匹配(欧拉图+最小费用流)
problem
给定 nnn 个数 {ai}\{a_i\}{ai},其中 kkk 个 aia_iai 是奇数,再给一个 n×nn\times nn×n 的矩阵 {ci,j}\{c_{i,j}\}{ci,j},无论是 aaa 还是 ccc,都保证是非负整数。
现在可以做一类操作:将 ai−1,aj−1a_i-1,a_j-1ai−1,aj−1,花费 ci,jc_{i,j}ci,j 代价,i,ji,ji,j 可以相同。
要求把所有的 {ai}\{a_i\}{ai} 全都变为 000。
求最小花费,无解输出 −1-1−1。
n≤50,k≤8n\le 50,k\le 8n≤50,k≤8,保证 ci,j=cj,ic_{i,j}=c_{j,i}ci,j=cj,i。
solution
显然,每次操作都会使得 (∑ai)−2(\sum a_i)-2(∑ai)−2。所以如果 ∑ai\sum a_i∑ai 是奇数,即 aia_iai 为奇数的 iii 有奇数个,则无解。
接下来再来解决有解的问题。
先考虑 k=0k=0k=0 的弱化版。
那就存在欧拉回路,要求每个点的入度和出度相同,经典网络流模型转化。
将每个点拆成两个点,各放左右部,与源/汇点的连边流量设置为 ai2\frac{a_i}22ai。
花费针对“关系”而言,左右部点之间连边流量无穷带花费。
直接跑最小费用流即可。
转化思考:
如果操作 i,ji,ji,j,就在图上连一条 (i,j)(i,j)(i,j) 的边。那么最后这张图可能有重边和若干个环。
发现这是一张欧拉图,存在欧拉回路。我们能找到一种定向方式使得每个点的入度和出度相同。
推出存在一种最优方案使得每个点的入度和出度相同。
将每个点拆成入度点和出度点,转化成匹配问题。
现在有几个特殊点是奇数,欧拉回路不存在,变成存在欧拉路径。
我们先通过若干次操作将这些奇数全都消成偶数,就又转化成了欧拉回路,就可以套用上面的方法。
转化思考:
我们通过对图上进行加边,使得这张图最后仍是存在欧拉回路的图。
由此推出存在一种最优方案使得奇数点的入度和出度只相差 111。
由于 kkk 非常小,我们大可直接状压枚举哪一半的奇数点是入度多 111,剩下的就肯定是出度多 111。
还是转化成了入度和出度二分图的匹配问题,仍然跑个最小费用流。
最后求个 min\minmin 就完了。
code
#include <bits/stdc++.h>
using namespace std;
#define maxn 200
#define inf 0x7f7f7f7f
struct node { int to, nxt, flow, cost; }E[maxn * maxn];
int head[maxn], dis[maxn], lst[maxn], a[maxn], b[maxn], id[maxn];
int c[maxn][maxn];
bool vis[maxn];
int n, cnt, m, s, t;
queue < int > q;void addedge( int u, int v, int flow, int cost ) {E[++ cnt] = { v, head[u], flow, cost }, head[u] = cnt;E[++ cnt] = { u, head[v], 0, - cost }, head[v] = cnt;
}bool SPFA() {memset( lst, -1, sizeof( lst ) );memset( dis, 0x7f, sizeof( dis ) );dis[s] = 0, q.push( s );while( ! q.empty() ) {int u = q.front(); q.pop(); vis[u] = 0;for( int i = head[u];~ i;i = E[i].nxt ) {int v = E[i].to;if( dis[v] > dis[u] + E[i].cost and E[i].flow ) {dis[v] = dis[u] + E[i].cost; lst[v] = i;if( ! vis[v] ) vis[v] = 1, q.push( v );}}}return ~ lst[t];
}int solve() {memset( head, -1, sizeof( head ) ), cnt = -1;for( int i = 1;i <= n;i ++ )for( int j = 1;j <= n;j ++ )addedge( i, j + n, inf, c[i][j] );for( int i = 1;i <= n;i ++ ) {addedge( s, i, a[i] + b[i] >> 1, 0 );addedge( i + n, t, a[i] - b[i] >> 1, 0 );}int ans = 0;while( SPFA() ) {int flow = inf;for( int i = lst[t];~ i;i = lst[E[i ^ 1].to] )flow = min( flow, E[i].flow );ans += flow * dis[t];for( int i = lst[t];~ i;i = lst[E[i ^ 1].to] ) {E[i ^ 1].flow += flow;E[i].flow -= flow;}}return ans;
}int main() {scanf( "%d", &n ); s = 0, t = n << 1 | 1;for( int i = 1;i <= n;i ++ ) {scanf( "%d", &a[i] );if( a[i] & 1 ) id[m ++] = i;}for( int i = 1;i <= n;i ++ )for( int j = 1;j <= n;j ++ )scanf( "%d", &c[i][j] );if( m & 1 ) return ! puts("-1");int ans = inf;for( int i = 0;i < (1 << m);i ++ ) {for( int j = 0;j < m;j ++ )if( i >> j & 1 ) b[id[j]] = 1;else b[id[j]] = -1;if( __builtin_popcount( i ) ^ (m >> 1) ) continue;ans = min( ans, solve() );}printf( "%d\n", ans );return 0;
}
一般图带权多重匹配(欧拉图+最小费用流)相关推荐
- 二分图带权匹配、最佳匹配与KM算法
---------------------以上转自ByVoid神牛博客,并有所省略. [二分图带权匹配与最佳匹配] 什么是二分图的带权匹配?二分图的带权匹配就是求出一个匹配集合,使得集合中边的权值 ...
- 【网络流24题】解题报告:E 、圆桌问题(最大流求二分图多重匹配)
E .圆桌问题(最大流求二分图多重匹配)[省选/NOI- ] 可以直观的想到,二分图的左边是单位,右边是桌子 由于题目的限制 每个单位只能在一个桌子坐一个人 所以我们就把每个单位向各个桌子连一道流量为 ...
- POJ - 2289 Jamie's Contact Groups(二分图多重匹配)
题目链接:点击查看 题目大意:给出n个联系人,以及m个分组,现在需要将n个联系人分到m个分组中,需要满足让人数最多的组的人数最少,输出这个值 题目分析:因为是让最大值最小,所以肯定是要用二分解决,因为 ...
- POJ - 3189 Steady Cow Assignment(二分图多重匹配)
题目链接:点击查看 题目大意:给出n只奶牛以及m个牛棚,接下来给出一个n*m的矩阵,给出每一只奶牛对于每个牛棚的喜爱度,按照降序给出,从rank1到rankm,现在问如何分配牛棚能让所有奶牛中最高的r ...
- HDU - 3605 Escape(二分图多重匹配-网络流最大流+思维建边+状态压缩)
题目链接:点击查看 题目大意:到世界末日了,现在人们要逃离去其他的星球,现在给出n个人以及m个星球,再给出每个人可以前往的星球,最后给出每个星球的容量,题目问最多能让多少个人逃离 题目分析:这个题读完 ...
- CH - 6803 导弹防御塔(二分图最大匹配-多重匹配(拆点法))
题目链接:点击查看 题目大意:给出n个炮塔,再给出m个敌人,每个炮塔都可以持续发射导弹,不过发射导弹的时间是t1秒,炮塔冷却的时间是t2分钟,炮弹飞行的速度是v,炮塔和敌人之间的距离按照欧几里得距离计 ...
- 图论:二分图多重匹配
使用最大流和费用流解决二分图的多重匹配 之前编辑的忘存了好气啊.. 本来打算学完二分图的乱七八糟的匹配之后再去接触网络流的,提前撞到了 之前我们说的二分图最大匹配和二分图最大权匹配有一个特点,那就是没 ...
- Uvalive3353 Optimal Bus Route Design 带权二分图匹配
题目描述:给出一个有向带权图,现在要求在图中找出若干个环,使得每个点恰好在一个环里,且所有环的距离之和最小,如果不能使每个点恰好在一个环里,输出"N". 思路: 将每个点u拆成u和 ...
- 带权二分图匹配(最小费用最大流) 8.2牛客暑期多校训练营五 E
E.room | 时间限制:1 秒 | 内存限制:256M Nowcoder University has 4n students and n dormitories ( Four students ...
最新文章
- SpringMVC请求流程
- ASP.NET Core SameSite 设置引起 Cookie 在 QQ 浏览器中不起作用
- VC++动态链接库DLL编程深入浅出
- 程序设计与算法----递归汉诺塔问题
- Android ListView 指定显示最后一行
- Django 2.0 报错解决方案----持续更新中
- nodejs fs模块
- 八大排序算法—源代码(c语言)
- VC密码正确无法登陆。证书过期。处理。
- android设置默认程序图标,android – 更改默认系统应用程序图标
- aws篇1 aws-cli的使用
- 阿里云Centos6数据盘扩容的问题处理
- 计算机知识动画片,这些好看的动画片里竟然藏着许多知识点!(内附2019年观影日历)...
- zoj 3551 Bloodsucker (概率dp)
- Cesium学习资源
- 从头开始绘制一个圆锥体
- 计算机网络——各层次网络互联设备
- C# QRCode生成二维码,支持中文,有utf
- 桌面上 计算机 图标打不开,突然间电脑桌面上的所有图标都打不开了,怎么回事,求大神讲解...
- Spyder 打开失败问题解决
热门文章
- 有些人还活着,被你一按就死了。。 | 今日最佳
- 编程语言的“别样”编年史
- 天赋差的程序员,难道就只能半途而废吗?
- c语言md5函数 linux,Linux下C语言计算文件的md5值(长度32)
- java 方法执行结束局部变量释放_Java方法执行的内存模型
- java反射 获取局部变量_Java反射:如何获取变量的名称?
- java中如何运行小程序_一起学java(一)——运行第一个小程序
- c语言怎样表示运行时间,C语言运行时间
- qtabwidget设置tab高度_VC|富文本编辑框CRichEditCtrl的字体与段落设置
- python求函数极值_python 遗传算法求函数极值的实现代码