HDU 1569 方格取数(2)(最大流最小割の最大权独立集)
Description
Input
Output
题目大意:这么短还中文就没大意了,唯一要注意的就是输入的第一个是行第二个是列……
思路:这题为最大权独立集(所选的点之间都没有边)。建立一个最大流的二分图,i+j为偶数的放左边,源点S连一条边到它,容量为格子里的数,其余放右边,连一条边到汇点T,容量还是格子里的数,相邻的都从左到右连一条边,容量为无穷大。所有数字之和减去最大流即为答案。
小证明:这样构图求出的最大流为最小权覆盖集(所有边至少被一个点覆盖),详见POJ 3308 Paratroopers(最大流最小割の最小点权覆盖)
而最小权覆盖集与最大权独立集是对偶图,把最小权覆盖集里的点都取反,就可以得到一个最大权独立集,所以总权 = 最小权覆盖集 + 最大权独立集。详见二分图中的对偶问题
代码(15MS):
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std; const int MAXN = ;
const int MAXE = ;
const int INF = 0x3fff3fff; struct SAP {
int head[MAXN], dis[MAXN], pre[MAXN], cur[MAXN], gap[MAXN];
int to[MAXE], next[MAXE], flow[MAXE];
int n, st, ed, ecnt; void init() {
memset(head, , sizeof(head));
ecnt = ;
} void add_edge(int u, int v, int c) {
to[ecnt] = v; flow[ecnt] = c; next[ecnt] = head[u]; head[u] = ecnt++;
to[ecnt] = u; flow[ecnt] = ; next[ecnt] = head[v]; head[v] = ecnt++;
//printf("%d->%d flow = %d\n", u, v, c);
} void bfs() {
memset(dis, 0x3f, sizeof(dis));
queue<int> que; que.push(ed);
dis[ed] = ;
while(!que.empty()) {
int u = que.front(); que.pop();
++gap[dis[u]];
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(flow[p ^ ] && dis[v] > n) {
dis[v] = dis[u] + ;
que.push(v);
}
}
}
} int Max_flow(int ss, int tt, int nn) {
st = ss; ed = tt; n = nn;
int ans = , minFlow = INF, u;
for(int i = ; i <= n; ++i) {
cur[i] = head[i];
gap[i] = ;
}
u = pre[st] = st;
bfs();
while(dis[st] < n) {
bool flag = false;
for(int &p = cur[u]; p; p = next[p]) {
int &v = to[p];
if(flow[p] && dis[u] == dis[v] + ) {
flag = true;
minFlow = min(minFlow, flow[p]);
pre[v] = u;
u = v;
if(u == ed) {
ans += minFlow;
while(u != st) {
u = pre[u];
flow[cur[u]] -= minFlow;
flow[cur[u] ^ ] += minFlow;
}
minFlow = INF;
}
break;
}
}
if(flag) continue;
int minDis = n - ;
for(int p = head[u]; p; p = next[p]) {
int &v = to[p];
if(flow[p] && minDis > dis[v]) {
minDis = dis[v];
cur[u] = p;
}
}
if(--gap[dis[u]] == ) break;
gap[dis[u] = minDis + ]++;
u = pre[u];
}
return ans;
}
} G; int n, m;
int mat[][]; int main() {
while(scanf("%d%d", &n, &m) != EOF) {
for(int i = ; i <= n; ++i)
for(int j = ; j <= m; ++j) scanf("%d", &mat[i][j]);
G.init();
int ss = n * m + , tt = n * m + ;
int cnt = , sum = ;
for(int i = ; i <= n; ++i) {
for(int j = ; j <= m; ++j) {
++cnt; sum += mat[i][j];
if((i + j) & ) {
G.add_edge(ss, cnt, mat[i][j]);
if(j != ) G.add_edge(cnt, cnt - , INF);
if(i != ) G.add_edge(cnt, cnt - m, INF);
if(j != m) G.add_edge(cnt, cnt + , INF);
if(i != n) G.add_edge(cnt, cnt + m, INF);
}
else G.add_edge(cnt, tt, mat[i][j]);
}
}
printf("%d\n", sum - G.Max_flow(ss, tt, tt));
}
}
HDU 1569 方格取数(2)(最大流最小割の最大权独立集)的更多相关文章
- HDU 1569 方格取数(2) (最小割)
方格取数(2) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Su ...
- 网络流(最大流) HDU 1565 方格取数(1) HDU 1569 方格取数(2)
HDU 1565 方格取数(1) 给你一个n*n的格子的棋盘,每个格子里面有一个非负数.从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取的数所在的2个格子不能相邻,并且取出的数的 ...
- HDU 1569 方格取数(2)
方格取数(2) Time Limit: 5000ms Memory Limit: 32768KB This problem will be judged on HDU. Original ID: 15 ...
- HDU 1569 - 方格取数(2) - [最大点权独立集与最小点权覆盖集]
嗯,这是关于最大点权独立集与最小点权覆盖集的姿势,很简单对吧,然后开始看题. 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1569 Time Limi ...
- HDU 1565 - 方格取数(1) - [状压DP][网络流 - 最大点权独立集和最小点权覆盖集]
题目链接:https://cn.vjudge.net/problem/HDU-1565 Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32 ...
- HDU 1565 1569 方格取数(最大点权独立集)
HDU 1565 1569 方格取数(最大点权独立集) 题目链接 题意:中文题 思路:最大点权独立集 = 总权值 - 最小割 = 总权值 - 最大流 那么原图周围不能连边,那么就能够分成黑白棋盘.源点 ...
- [HDU 1565+1569] 方格取数
HDU 1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others ...
- HDU 1565&1569 方格取数系列(状压DP或者最大流)
方格取数(2) Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total S ...
- HDU 1565 方格取数(1) 轮廓线dp
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=1565 方格取数(1) Time Limit: 10000/5000 MS (Java/Others) ...
随机推荐
- ubuntu网卡配置及安装ssh服务
1.ubuntu网卡配置 1.查看网卡名称 ip a 2.进行编辑网卡配置文件 sudo vi /etc/network/interfaces 更改网卡配置文件添加内容修改内容如下:下面的enp0s3 ...
- Win10英文系统 JDK1.8安装及环境变量配置
前提 今天换新电脑了,需要重新安装一遍JDK.写个随笔记录一下整个过程. 下载 官网上JDK已经出到10了,但是回忆起JDK9都有各种坑(不支持一些软件),决定还是用JDK8. 下载地址: http: ...
- MAC系统 输入管理员账户密码 登录不上
mac新系统改密码~管理员 升级10.13.2后,很多不会操作了, 那天把系统管理员设置成了普通管理,就不能打开个别软件了, 贼尴尬~~~ 后来找blog才解决,现在分享下~~ http://www. ...
- vue 新属性学习
1, $listeners 父级元素 <base-input v-on:focus.native="onFocus"></base-input> 子级元素 ...
- 使用Letsencrypt做SSL certificate
为什么要使用Letsencrypt做SSL certificate? 最简单直接的原因是免费.但是免费存在是否靠谱的问题,尤其是对安全要求比较高的网站,需要考虑使用letsencrypt的安全性是否符 ...
- 端午节佳节从CSDN博客搬家来这,请多多指教
端午节佳节从CSDN博客搬家来博客园,请多多指教
- java枚举常见用法
用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... .现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法. p ...
- java中子类会继承父类的构造方法吗?
参考: https://blog.csdn.net/wangyl_gain/article/details/49366505
- python教程(二)·循环语句
计算机程序中常常需要重复执行某些语句,我们总不能将同一语句写上百遍吧?所以在python中,当然其它计算机语言也是,有一种语句可以重复执行相同的操作,这种语句就是 "循环语句",而 ...
- 中国大学MOOC-C程序设计(浙大翁恺)—— 时间换算
时间换算(10分) 题目内容: UTC是世界协调时,BJT是北京时间,UTC时间相当于BJT减去8.现在,你的程序要读入一个整数,表示BJT的时和分.整数的个位和十位表示分,百位和千位表示小时.如果小 ...