uva12534 Binary Matrix 2(最小费用最大流)
http://blog.csdn.net/qq564690377/article/details/17082055
做的时候觉得明显是费用流,但是真的不知道怎么建图,看了上面的博客会稍微清晰一点。后面再补一点细节吧,然后发现这道题用自己平时的费用流模板是水不过去的,所以找了份别人AC的代码弄了个zkw最小费用流的模板上来,算是存下模板吧。
补充点个人的理解吧,个人的网络流做的题还是太少了,所以想不到怎么建模,其实感觉上还是比较直接的一个行列二分图建模。首先就是枚举最后有多少个1剩下来,假设当前的已经有cur个1了,然后我要达到tot,那么每一行应该有tot/n个,每一列应该有tot/m个,所以我们可以对每行建一个点,对每列建一个点,从源点到行的点限流tot/n,列的点到汇点限流tot/m,这样的话当满流的时候其实就能保证每一行的1相等,每一列的1也相等。然后建边的时候就是每个处于(i,j)的点和i行j列的点连一条边,假设原本是1就费用为0,原本是0就费用为1.那么按照这样跑一遍费用流,费用x就是图里面需要由0变成1的点的个数,我们只需要再求出y,即图里由1变成0的个数就可以了。那么y等于多少呢? 不难发现图中多出来的1应该满足 x-y=tot-cur 所以y=x+cur-tot 所以最后的费用是x+y=2*x+cur-tot。
http://blog.sina.com.cn/s/blog_61034ad90100gwdw.html
上面的博客研究了spfa的网络流和zkw的网络流,可能zkw网络流会比较适用在二分图,稠密图上吧。
#pragma warning(disable:4996)
#include <iostream>
#include <cstring>
#include <string>
#include <vector>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <queue>
using namespace std; #define ll long long
#define eps 1e-8
#define maxn 100
#define maxe 4000
#define inf 0x3f3f3f3f
using namespace std; char b[50][50];
int n, m; /*int siz; struct Edge{
int u, v, nxt, cap, cost;
}edge[maxe];
int head[maxn]; struct MinCostMaxFlow
{
queue<int> que;
int add; // edges number
int vn; // total vertex number
int cost[maxn], in[maxn], pre[maxn];
bool vis[maxn];
void init(){
add = 0; vn = siz + 10; memset(head, -1, sizeof(head));
while (!que.empty()) que.pop();
}
void insert(int u, int v, int w, int c){
edge[add].u = u; edge[add].v = v; edge[add].cap = w; edge[add].cost = c;
edge[add].nxt = head[u]; head[u] = add++;
edge[add].u = v; edge[add].v = u; edge[add].cap = 0; edge[add].cost = -c;
edge[add].nxt = head[v]; head[v] = add++;
} bool spfa(int s, int e){
memset(cost, 0x3f3f3f3f, sizeof(cost));
memset(in, 0, sizeof(in));
memset(vis, 0, sizeof(vis));
cost[s] = 0; pre[s] = -1;
que.push(s); vis[s] = true; in[s]++;
while (!que.empty()){
int u = que.front(); que.pop();
vis[u] = false;
for (int i = head[u]; i != -1; i = edge[i].nxt){
int v = edge[i].v;
if (edge[i].cap > 0 && cost[v] > cost[u] + edge[i].cost){
cost[v] = cost[u] + edge[i].cost; pre[v] = i;
if (!vis[v]){
que.push(v); vis[v] = true; in[v]++;
if (in[v] > vn) return false;
}
}
}
}
if (cost[e] < inf) return true;
else return false;
}
int mincostmaxflow(int s, int e){
int mincost = 0, maxflow = 0;
while (spfa(s, e)){
int flow = inf;
for (int i = pre[e]; i != -1; i = pre[edge[i].u]){
flow = min(flow, edge[i].cap);
}
maxflow += flow;
for (int i = pre[e]; i != -1; i = pre[edge[i].u]){
edge[i].cap -= flow;
edge[i ^ 1].cap += flow;
}
mincost += cost[e] * flow;
}
return mincost;
}
}net;
*/ struct Edge
{
int u, v, cap, cost, nxt;
Edge(int _u, int _v, int _cap, int _cost, int _nxt) :
u(_u), v(_v), cap(_cap), cost(_cost), nxt(_nxt){}
Edge(){};
}edge[maxe];
int head[maxn]; struct ZKW_MinCostMaxFlow {
int add;
int cur[maxn];
int dis[maxn];
bool inq[maxn];
queue<int> q;
bool vis[maxn]; int ss, tt, n;
int min_cost, max_flow; void init() {
memset(head, -1, sizeof(head));
add = 0;
} void insert(int u, int v, int cp, int ct) {
edge[add] = Edge(u, v, cp, ct, head[u]);
head[u] = add++;
edge[add] = Edge(v, u, 0, -ct, head[v]);
head[v] = add++;
} int aug(int u, int flow) {
if (u == tt) return flow;
vis[u] = true;
for (int i = cur[u]; i != -1; i = edge[i].nxt) {
int v = edge[i].v;
if (edge[i].cap && !vis[v] && dis[u] == dis[v] + edge[i].cost) {
int tmp = aug(v, min(flow, edge[i].cap));
edge[i].cap -= tmp;
edge[i ^ 1].cap += tmp;
cur[u] = i;
if (tmp) return tmp;
}
}
return 0;
}
bool modify_label() {
int d = inf;
for (int u = 0; u < n; u++) if (vis[u])
for (int i = head[u]; i != -1; i = edge[i].nxt) {
int v = edge[i].v;
if (edge[i].cap && !vis[v])
d = min(d, dis[v] + edge[i].cost - dis[u]);
}
if (d == inf) return false;
for (int i = 0; i < n; ++i) if (vis[i]) {
vis[i] = false;
dis[i] += d;
}
return true;
} pair<int, int> mincostmaxflow(int s, int t, int _n) {
ss = s, tt = t, n = _n;
min_cost = max_flow = 0;
for (int i = 0; i < n; i++) dis[i] = 0;
while (true) {
for (int i = 0; i < n; i++) cur[i] = head[i];
while (true) {
for (int i = 0; i < n; i++) vis[i] = 0;
int tmp = aug(s, inf);
if (tmp == 0) break;
max_flow += tmp;
min_cost += tmp * dis[ss];
}
if (!modify_label()) break;
}
return make_pair(min_cost, max_flow);
}
}net; int main()
{
int T; cin >> T; int ca = 0;
while (T--){
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) scanf("%s", b[i]);
int tot = 0;
for (int i = 0; i < n; ++i){
for (int j = 0; j < m; ++j){
if (b[i][j] == '1') tot++;
}
}
int ans = min(n*m - tot, tot);
for (int i = 1; i <= n*m; ++i){
if (i%n != 0 || i%m != 0) continue;
if (abs(tot - i) >= ans) continue;
net.init();
int src = n + m, sink = src + 1;
for (int k = 0; k < n; ++k){
net.insert(src, k, i / n, 0);
}
for (int k = n; k < n + m; k++){
net.insert(k, sink, i / m, 0);
}
for (int x = 0; x < n; x++){
for (int j = 0; j < m; j++){
if (b[x][j] == '1') net.insert(x, j + n, 1, 0);
else net.insert(x, j + n, 1, 1);
}
}
ans = min(ans, net.mincostmaxflow(src, sink,sink+1).first * 2 + tot - i);
}
printf("Case %d: %d\n", ++ca, ans);
}
return 0;
}
uva12534 Binary Matrix 2(最小费用最大流)的更多相关文章
- [poj] 3422 Kaka's Matrix Travels || 最小费用最大流
原题 给一个N*N的方阵,从[1,1]到[n,n]走K次,走过每个方格加上上面的数,然后这个格上面的数变为0.求可取得的最大的值. 要求最大值,所以把边权全为负跑最小费用即可.因为只有第一次经过该点的 ...
- UVa11082 Matrix Decompressing(最小费用最大流)
题目大概有一个n*m的矩阵,已知各行所有数的和的前缀和和各列所有数的和的前缀和,且矩阵各个数都在1到20的范围内,求该矩阵的一个可能的情况. POJ2396的弱化版本吧..建图的关键在于: 把行.列看 ...
- hdu 2686 Matrix 最小费用最大流
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2686 Yifenfei very like play a number game in the n*n ...
- POJ 3422 Kaka's Matrix Travels (最小费用最大流)
POJ 3422 Kaka's Matrix Travels 链接:http://poj.org/problem? id=3422 题意:有一个N*N的方格,每一个方格里面有一个数字.如今卡卡要从左上 ...
- POJ 3422 Kaka's Matrix Travels 【最小费用最大流】
题意: 卡卡有一个矩阵,从左上角走到右下角,卡卡每次只能向右或者向下.矩阵里边都是不超过1000的正整数,卡卡走过的元素会变成0,问卡卡可以走k次,问卡卡最多能积累多少和. 思路: 最小费用最大流的题 ...
- poj3422 Kaka's Matrix Travels(最小费用最大流问题)
/* poj3422 Kaka's Matrix Travels 不知道 k次 dp做为什么不对??? 看了大牛的代码,才知道还可以这样做! 开始没有理解将a 和 a‘ 之间建立怎样的两条边,导致程序 ...
- hdu 2686 Matrix && hdu 3367 Matrix Again (最大费用最大流)
Matrix Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Subm ...
- HDU3376 最小费用最大流 模板2
Matrix Again Time Limit: 5000/2000 MS (Java/Others) Memory Limit: 102400/102400 K (Java/Others)To ...
- hdu 3395(KM算法||最小费用最大流(第二种超级巧妙))
Special Fish Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Tota ...
随机推荐
- postgresql 函数 参数为复合类型
postgresql没有存储过程,但是函数功能很强大. 在近期开发的电商管理平台中,对于产品的类目管理,设计时有个属性字段,设为字符数组,但是EF不支持数组的操作,所以在添加和修改类目时,需要对属性的 ...
- oracle 分析函数(笔记)
分析函数是oracle数据库在9i版本中引入并在以后版本中不断增强的新函数种类.分析函数提供好了跨行.多层次聚合引用值的能力.分析函数所展现的效果使用传统的SQL语句也能实现,但是实现方式比较复杂,效 ...
- Gearman 安装使用教程
Gearman是一个分发任务的程序框架,可以用在各种场合,Gearman更偏向于任务分发功能.它的任务分布非常简单,简单得可以只需要用脚本即可完成. Gearman 分布式任务实现原理上只用到2个字段 ...
- 上传图片的回调函数,callback作为一个函数针对回调函数
Tool.ImageUpload = function (selector, callback) { /// <summary>图片上传</summary> /// <p ...
- 关于 ajax 动态返回数据 css 以及 js 失效问题
ajax 毕竟是异步的 所以动态加载出来的数据 难免遇到 css 或者 js 失效的问题,所以要动态加载 css ji等文件了 1.公共方法 load //动态加载 js /css function ...
- JAVA内部类(转)
源出处:JAVA内部类 在java语言中,有一种类叫做内部类(inner class),也称为嵌入类(nested class),它是定义在其他类的内部.内部类作为其外部类的一个成员,与其他成员一样, ...
- EF之外键Include() left join
项目中用EF实现外键查询出的数据, 查询数量正确, 但实现返回数据集数量不对 //DbContext.cs HasRequired(s => s.ClassRoom) .WithMany() . ...
- 最大后验估计(MAP)
最大后验估计是根据经验数据获得对难以观察的量的点估计.与最大似然估计类似,但是最大的不同时,最大后验估计的融入了要估计量的先验分布在其中.故最大后验估计可以看做规则化的最大似然估计. 首先,我们回顾上 ...
- 从一个Activity返回上一个Activity
从一个Activity返回上一个Activity 要求:保留上一个Activity的数据 方法: 第一步:从Activity1转向Activity2时,用startActivityForResult而 ...
- 【转载】openldap 备份与导入 及相关问题--扩展
http://www.cnblogs.com/ccdc/p/3356518.html 摘要: 对openldap进行备份时,直接使用slapcat命令进行备份,使用ldapadd还原出现问题及解决. ...