51nod 算法马拉松4 D装盒子(网络流 / 二分图最优匹配)
第一行一个数N表示盒子的个数。
接下来N行,每行两个正整数,表示每个盒子的长度和宽度。
所有整数都是正的(N,以及盒子的长宽),且不超过200。
一行一个整数表示最终最小的占地面积。
3
1 1
1 2
2 1
4 想了很久,发现具有二分图的性质:每个点只能被包含在另外一个点当中。那么拆点,然后A可以被包含在B中就由左侧的A向右侧的B建一条边,这时构成一个二分图.
由于题目要求是的占地面积最小,那么考虑最大匹配时的连边情况,若最大匹配有A->B的这一条边存在,也就说明A被放在了B中,那么占地面积是不要包括A的面积的,所以考虑连边时,将A->B的边权值设为A的面积,那么最后答案就是所有点面积的总和 减去 最优匹配的权值和。 这里n<=200,所以考虑要使用N^3的最优匹配. 同样可以用二分图的题一定可以用网络流,然后网络流跑了一发(最小费用最大流)。
最后二分图最优匹配32ms,而网络流64ms
#pragma comment(linker, "/STACK:1677721600")
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <bitset>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf (-((LL)1<<40))
#define lson k<<1, L, (L + R)>>1
#define rson k<<1|1, ((L + R)>>1) + 1, R
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define rep(i, a, b) for(int i = a; i <= b; i ++)
#define dec(i, a, b) for(int i = a; i >= b; i --) //typedef __int64 LL;
typedef long long LL;
typedef pair<int, int> Pair;
const int MAXN = + ;
const int MAXM = ;
const double eps = 1e-;
LL MOD = ; int n; struct KM {
const static int maxn = 1e3 + ;
int A[maxn], B[maxn];
int visA[maxn], visB[maxn];
int match[maxn], slack[maxn], Map[maxn][maxn];
int M, H; void add(int u, int v, int w) {
Map[u][v] = w;
}
bool find_path ( int i ) {
visA[i] = true;
for ( int j = ; j < H; j++ ) {
if ( !visB[j] && A[i] + B[j] == Map[i][j] ) {
visB[j] = true;
if (match[j] == - || find_path(match[j])) {
match[j] = i;
return true;
}
} else if ( A[i] + B[j] > Map[i][j] ) //j属于B,且不在交错路径中
slack[j] = min(slack[j], A[i] + B[j] - Map[i][j]);
}
return false;
} int solve (int M, int H) {
this->M = M; this->H = H;
int i, j, d;
memset(A, , sizeof(A));
memset(B, , sizeof(B));
memset(match, -, sizeof(match));
for ( i = ; i < M; i++ )
for ( j = ; j < H; j++ )
A[i] = max (Map[i][j], A[i]);
for ( i = ; i < M; i++ ) {
for ( j = ; j < H; j++ )
slack[j] = INF;
while ( ) {
memset(visA, , sizeof(visA));
memset(visB, , sizeof(visB));
if ( find_path ( i ) ) break; //从i点出发找到交错路径则跳出循环
for ( d = INF, j = ; j < H; j++ ) //取最小的slack[j]
if (!visB[j] && d > slack[j]) d = slack[j];
for ( j = ; j < M; j++ ) //集合A中位于交错路径上的-d
if ( visA[j] ) A[j] -= d;
for ( j = ; j < H; j++ ) //集合B中位于交错路径上的+d
if ( visB[j] ) B[j] += d;
else slack[j] -= d; //注意修改不在交错路径上的slack[j]
}
}
int res = ;
for ( j = ; j < H; j++ )
res += Map[match[j]][j];
return res;
}
}km;//点从0开始编号 struct Node {
int w, h;
bool operator < (const Node &A) const {
if(w != A.w) return w < A.w;
return h < A.h;
}
bool operator == (const Node &A) const {
return w == A.w && h == A.h;
}
}r[MAXN]; void handle() {
sort(r + , r + n + );
int cnt = ;
rep (i, , n) if(!(r[i] == r[i - ])) {
r[++cnt] = r[i];
}
n = cnt;
} int solve() {
int ans = ;
rep (i, , n) {
scanf("%d %d", &r[i].w, &r[i].h);
}
handle();
rep (i, , n) ans += r[i].w * r[i].h;
rep (i, , n) rep (j, , n) if(i != j && r[i].h >= r[j].h && r[i].w >= r[j].w) {
km.add(j - , i - , r[j].w * r[j].h);
}
ans -= km.solve(n, n);
cout << ans << endl;
} int main()
{
// FIN;
cin >> n;
solve();
return ;
}
#pragma comment(linker, "/STACK:1677721600")
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <cmath>
#include <ctime>
#include <bitset>
#include <vector>
#include <cstdio>
#include <cctype>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define inf (-((LL)1<<40))
#define lson k<<1, L, (L + R)>>1
#define rson k<<1|1, ((L + R)>>1) + 1, R
#define mem0(a) memset(a,0,sizeof(a))
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a, b) memset(a, b, sizeof(a))
#define FIN freopen("in.txt", "r", stdin)
#define FOUT freopen("out.txt", "w", stdout)
#define rep(i, a, b) for(int i = a; i <= b; i ++)
#define dec(i, a, b) for(int i = a; i >= b; i --) //typedef __int64 LL;
typedef long long LL;
typedef pair<int, int> Pair;
const int MAXN = + ;
const int MAXM = ;
const double eps = 1e-;
LL MOD = ; //以下是使用邻接表存边,不是使用vector,某些时候比上述要稍快一下
/*******************************************************************/
struct Edge {
int to, cap, flow, cost, next;
Edge(){}
Edge(int _n, int _v, int _c, int _f, int _cost){
next = _n; to = _v; cap = _c;
flow = _f; cost = _cost;
}
}; struct MCMF
{
int n, m, src, des;
int head[MAXN], tot;
Edge edges[MAXM];
int inq[MAXN];
int d[MAXN];
int p[MAXN];
int a[MAXN]; void init(int n, int src, int des) {
this->tot = ;
this->n = n;
this->src = src;
this->des = des;
mem1(head);
} void add_edge(int from, int to, int cap, int cost) {
edges[tot] = Edge(head[from], to, cap, , cost);
head[from] = tot ++;
edges[tot] = Edge(head[to], from, , , -cost);
head[to] = tot ++;
} bool bellman_ford(int s, int t, int& flow, int& cost) {
for(int i = ; i < n; i ++) {
d[i] = INF;
inq[i] = ;
}
d[s] = ; inq[s] = ;
p[s] = ; a[s] = INF; queue<int>Q;
Q.push(s);
while(!Q.empty()) {
int u = Q.front(); Q.pop();
inq[u] = false;
for(int i = head[u]; i != -; i = edges[i].next) {
int v = edges[i].to;
if(edges[i].cap > edges[i].flow && d[v] > d[u] + edges[i].cost) {
d[v] = d[u] + edges[i].cost;
p[v] = i;
a[v] = min(a[u], edges[i].cap - edges[i].flow);
if(!inq[v]) {
Q.push(v);
inq[v] = ;
}
}
}
}
if(d[t] >= ) return false; flow += a[t];
cost += d[t] * a[t]; int u = t;
while(u != s) {
edges[p[u]].flow += a[t];
edges[p[u]^].flow -= a[t];
u = edges[p[u]^].to;
}
return true;
} int min_cost() {
int flow = , cost = ;
while(bellman_ford(src, des, flow, cost));
return cost;
} }mcmf;
/***************************************************************/ struct Node {
int w, h;
bool operator < (const Node &A) const {
if(w != A.w) return w < A.w;
return h < A.h;
}
bool operator == (const Node &A) const {
return w == A.w && h == A.h;
}
}r[MAXN];
int n; void handle() {
sort(r + , r + n + );
int cnt = ;
rep (i, , n) if(!(r[i] == r[i - ])) {
r[++cnt] = r[i];
}
n = cnt;
} int solve() {
int ans = ;
rep (i, , n) {
scanf("%d %d", &r[i].w, &r[i].h);
}
handle();
mcmf.init( * (n + ), , * n + );
rep (i, , n) {
ans += r[i].w * r[i].h;
mcmf.add_edge(mcmf.src, * i - , , );
mcmf.add_edge( * i, mcmf.des, , );
}
rep (i, , n) rep (j, , n) if(i != j && r[i].h >= r[j].h && r[i].w >= r[j].w) {
mcmf.add_edge( * j - , * i, , -r[j].w * r[j].h);
}
ans += mcmf.min_cost();
cout << ans << endl;
} int main()
{
// FIN;
cin >> n;
solve();
return ;
}
51nod 算法马拉松4 D装盒子(网络流 / 二分图最优匹配)的更多相关文章
- 网络流——二分图最优匹配KM算法
前言 其实这个东西只是为了把网络流的内容凑齐而写的(反正我是没有看到过这样子的题不知道田忌赛马算不算) 算法过程 我们令左边的点(其实二分图没有什么左右)为女生,右边的点为男生,那么: 为每一个女生定 ...
- 51NOD 算法马拉松8
题目戳这里:51NOD算法马拉松8 某天晚上kpm在玩OSU!之余让我看一下B题...然后我就被坑进了51Nod... A.还是01串 水题..怎么乱写应该都可以.记个前缀和然后枚举就行了.时间复杂度 ...
- 51nod 算法马拉松 34 Problem D 区间求和2 (FFT加速卷积)
题目链接 51nod 算法马拉松 34 Problem D 在这个题中$2$这个质数比较特殊,所以我们先特判$2$的情况,然后仅考虑大于等于$3$的奇数即可. 首先考虑任意一个点对$(i, j)$ ...
- 随便玩玩系列之一:SPOJ-RNG+51nod 算法马拉松17F+51nod 1034 骨牌覆盖v3
先说说前面的SPOJ-RNG吧,题意就是给n个数,x1,x2,...,xn 每次可以生成[-x1,x1]范围的浮点数,把n次这种操作生成的数之和加起来,为s,求s在[A,B]内的概率 连续形的概率 假 ...
- 51Nod 算法马拉松21(迎新年)
这次打算法马拉松是在星期五的晚上,发挥还算正常(废话,剩下的题都不会= =). 讲讲比赛经过吧. 8:00准时发题,拿到之后第一时间开始读. A配对,看上去像是二分图最大权匹配,一看范围吓傻了,先跳过 ...
- [hdu2255]奔小康赚大钱(二分图最优匹配、KM算法)
题目大意:求二分图的最优匹配(首先数目最大, 其次权值最大). 解题关键:KM算法 复杂度:$O(n^3)$ #include<cstdio> #include<cstring> ...
- 51Nod 算法马拉松22 开黑记
这是一场惨烈的开黑大战,始于全机房开黑指望刷进rank前十拿钱的壮志,终于被各路神犇怒踩成rank20,差点200点头盾不保的落魄,想起将近一年前ad和zcg等学长挤进rank10的壮举,不由得唏嘘, ...
- 51Nod 算法马拉松15 记一次悲壮而又开心的骗分比赛
OwO 故事的起源大概是zcg前天发现51Nod晚上有场马拉松,然后他就很开心的过去打了 神奇的故事就开始了: 晚上的时候我当时貌似正在写线段树?然后看见zcg一脸激动告诉我第一题有九个点直接输出B就 ...
- 51Nod 算法马拉松23 开黑记
惨啊……虽然开了半天黑,但是还是被dalao们踩了…… 第二次开黑,还是被卡在rank20了,我好菜啊……= = 写一写比赛经过吧…… 看到题之后习惯性都打开,A~D看上去似乎并没有什么思路,F应该是 ...
随机推荐
- mysql8新特性(一)
https://www.oschina.net/news/95325/mysql-8-0-ga-released http://blog.itpub.net/28218939/viewspace-21 ...
- linux 异常
1. NoRouteToHostException异常问题的原因及解决 (转自:http://performtest163.blog.163.com/blog/static/1400769642011 ...
- springcloud18---springCloudConfig
package com.itmuch.cloud; import org.springframework.beans.factory.annotation.Value; import org.spri ...
- Android 多媒体MediaPlayer使用详解
现在的手机功能越来越丰富了,遥想10年前,MP3,MP4,MP5,还是很流行的,博主当时读高中时很想拥有一台,可以听音乐和看电影.可是条件有限,学校也禁止此东西,所以只能偷偷的玩.而现在我们的手机也很 ...
- 【知识总结】CSS中样式覆盖优先顺序
层叠样式类型 类型: 1. 浏览器默认样式 2. 浏览器用户自定义样式 3. 外部样式表 4. 内部样式表 5. 内联样式表 顺序: 浏览器默认样式 < 浏览器用户自定义样式 < 外部样式 ...
- 如何把js的循环写成异步的
针对这里的问题:深入理解node.js异步编程:基础篇https://cnodejs.org/topic/533d6edbc2621e680800e0ea 这一节有一个代码:###4.1 Node.j ...
- OpenVAS安装过程
OpenVAS安装过程 安装过程 检查安装状况 命令行下输入opensav-check-setup,显示错误NO CA certificate file,并显示解决方法 创建证书 输入命令openva ...
- NOIP2016 T4 魔法阵 暴力枚举+前缀和后缀和优化
想把最近几年的NOIP T4都先干掉,就大概差16年的,所以来做一做. 然后这题就浪费了我一整天QAQ...果然还是自己太弱了QAQ 点我看题 还是pa洛谷的... 题意:给m个物品,每个物品有一个不 ...
- HDU 2485 Destroying the bus stations(费用流)
http://acm.hdu.edu.cn/showproblem.php?pid=2485 题意: 现在要从起点1到终点n,途中有多个车站,每经过一个车站为1时间,现在要在k时间内到达终点,问至少要 ...
- HTML和CSS美化 登入框的页面
<div id="leftbody"> <p class="p0">如果您感觉您的网站够炫美可以提交给我们!</p> < ...