题目大意:

给出n(\(\le 200\))个盒子,第i个盒子长\(x_i\),宽\(y_i\),一个盒子可以放入长宽都大于等于它的盒子里,并且每个盒子里只能放入一个盒子(可以嵌套),嵌套的盒子的占地面积等于最外层的盒子的占地面积,求最小的占地面积之和。

题目分析:

直接打了贪心,得了50分。用脑子想想就知道第3题怎么可能这么简单,果真。

本题的本质就是能不能给一个盒子找一个长宽都大于等于它的匹配。

  • 匈牙利+贪心:如果a可以包含b,则连一条边a<-b,然后按照面积从大到小跑匈牙利,如果能够找到一个匹配,就把这个盒子的面积减掉。
  • 费用流: 将一个盒子拆成两个点1~n, n+1~2n, 如果a可以包含b,就连一条a->b+n,流量为1(只能用1个),费用为\(S_b\)的边,最后从s向1n连流量为1,费用为0的边,从n+12n向t连流量为1,费用为0的边,跑最大费用最大流,将费用从总面积中减去。(费用流要去重)

code

匈牙利

#include<bits/stdc++.h>
using namespace std; namespace IO{
inline int read(){
int i = 0, f = 1; char ch = getchar();
for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
if(ch == '-') f = -1, ch = getchar();
for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
return i * f;
}
inline void wr(int x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) wr(x / 10);
putchar(x % 10 + '0');
}
}using namespace IO; const int N = 1000;
int n;
struct node{
int x, y;
inline bool operator < (const node &b) const{
return x*y < b.x*b.y;
}
}box[N];
bool vst[N << 2];
int mateR[N << 2], ecnt, adj[N << 2], nxt[N << 2], go[N << 2], ans, to[N][N]; inline bool hungry(int u){
for(int i = n; i > u; i--){
if(!to[u][i]) continue;
if(vst[i]) continue;
vst[i] = true;
if(!mateR[i] || hungry(mateR[i])){
mateR[i] = u;
return true;
}
}
return false;
} inline void addEdge(int u, int v){
nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v;
} int main(){
n = read();
for(int i = 1; i <= n; i++){
int x = read(), y = read();
box[i] = (node){x, y};
}
sort(box + 1, box + n + 1);
for(int i = 1; i <= n; i++){
ans += box[i].x * box[i].y;
for(int j = i + 1; j <= n; j++){
if(box[i].x <= box[j].x && box[i].y <= box[j].y)
to[i][j] = 1;
}
}
for(int i = n - 1; i >= 1; i--){
if(hungry(i)) ans -= box[i].x * box[i].y;
memset(vst, 0, sizeof vst);
}
wr(ans);
return 0;
}

费用流

#include<bits/stdc++.h>
using namespace std; namespace IO{
inline int read(){
int i = 0, f = 1; char ch = getchar();
for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
if(ch == '-') f = -1, ch = getchar();
for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
return i * f;
}
inline void wr(int x){
if(x < 0) putchar('-'), x = -x;
if(x > 9) wr(x / 10);
putchar(x % 10 + '0');
}
}using namespace IO; const int N = 205, OO = 0x3f3f3f3f;
int n, ecnt = 1, adj[N << 2], nxt[100050], go[100050], cap[100050], len[100050];
int src, des, dis[N << 2], cur[N << 2], sum;
struct node{
int x, y;
inline bool operator < (const node &b) const{
return x < b.x || (x == b.x && y < b.y);
}
}box[N], unik[N]; inline void addEdge(int u, int v, int c, int cost){
nxt[++ecnt] = adj[u], adj[u] = ecnt, go[ecnt] = v, cap[ecnt] = c, len[ecnt] = cost;
nxt[++ecnt] = adj[v], adj[v] = ecnt, go[ecnt] = u, cap[ecnt] = 0, len[ecnt] = -cost;
} int vt = 0;
inline bool SPFA(){
static queue<int> que;
static int vst[N << 2];
memset(vst, 0, sizeof vst);
while(!que.empty()) que.pop();
que.push(src);
for(int i = src; i <= des; i++) cur[i] = adj[i], dis[i] = -OO;
dis[src] = 0;
while(!que.empty()){
int u = que.front(); que.pop(); vst[u] = 0;
for(int e = adj[u]; e; e = nxt[e]){
int v = go[e];
if(dis[v] < dis[u] + len[e] && cap[e]){
dis[v] = dis[u] + len[e];
if(!vst[v]) vst[v] = 1, que.push(v);
}
}
}
return dis[des] != -OO;
} bool walk[N << 2];
inline int dinic(int u, int flow, int &ans){
if(u == des){
ans += flow * dis[u];
return flow;
}
int delta, ret = 0;
walk[u]=1;
for(int &e = cur[u]; e; e = nxt[e]){
int v = go[e];
if(!walk[v] && dis[v] == dis[u] + len[e] && cap[e]){
delta = dinic(v, min(cap[e], flow - ret), ans);
if(delta){
ret += delta, cap[e] -= delta, cap[e ^ 1] += delta;
if(flow == ret) break;
}
}
}
if(flow != ret) dis[u] = -OO;
return ret;
} int lenn;
inline void uni(){
lenn = 0;
sort(box+1,box+n+1);
for(int i = 1; i <= n; i++){
if(box[i].x != box[i - 1].x || box[i].y != box[i - 1].y)
unik[++lenn].x = box[i].x, unik[lenn].y = box[i].y;
}
}
int main(){
n = read(); src = 0, des = 2 * n + 1;
for(int i = 1; i <= n; i++) box[i].x = read(), box[i].y = read();
uni();
for(int i = 1; i <= lenn; i++){
sum += unik[i].x * unik[i].y;
for(int j = 1; j <= lenn; j++){
if(i == j) continue;
if(unik[j].x >= unik[i].x && unik[j].y >= unik[i].y)
addEdge(i, j + n, 1, unik[i].x*unik[i].y);
}
}
for(int i = 1; i <= n; i++) addEdge(src, i, 1, 0), addEdge(i + n, des, 1, 0);
while(SPFA()){
int ret = 0;
memset(walk, 0, sizeof walk);
dinic(src, OO, ret);
sum -= ret;
}
wr(sum), putchar('\n');
return 0;
}

NOIP 模拟 box - 费用流 / 匈牙利的更多相关文章

  1. 配置魔药 [NOIP模拟] [DP] [费用流]

    问题描述在<Harry Potter and the Chamber of Secrets>中,Ron 的魔杖因为坐他老爸的 Flying Car 撞到了打人柳,不幸被打断了,从此之后,他 ...

  2. 2019.6.1 模拟赛——[ 费用流 ][ 数位DP ][ 计算几何 ]

    第一题:http://codeforces.com/contest/1061/problem/E 把点集分成不相交的,然后跑费用流即可.然而错了一个点. #include<cstdio> ...

  3. BZOJ4946[Noi2017]蔬菜——线段树+堆+模拟费用流

    题目链接: [Noi2017]蔬菜 题目大意:有$n$种蔬菜,每种蔬菜有$c_{i}$个,每种蔬菜每天有$x_{i}$个单位会坏掉(准确来说每天每种蔬菜坏掉的量是$x_{i}-$当天这种蔬菜卖出量), ...

  4. 【BZOJ3252】攻略 DFS序+线段树(模拟费用流)

    [BZOJ3252]攻略 Description 题目简述:树版[k取方格数] 众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏. 今天他得到了一款新游戏<XX半岛> ...

  5. CF280D-k-Maximum Subsequence Sum【模拟费用流,线段树】

    正题 题目链接:https://www.luogu.com.cn/problem/CF280D 题目大意 一个长度为\(n\)的序列,\(m\)次操作 修改一个数 询问一个区间中选出\(k\)段不交子 ...

  6. BZOJ3291Alice与能源计划——匈牙利算法+模拟费用流

    题目描述 在梦境中,Alice来到了火星.不知为何,转眼间Alice被任命为火星能源部长,并立刻面临着一个严峻的考验.为 了方便,我们可以将火星抽象成平面,并建立平面直角坐标系.火星上一共有N个居民点 ...

  7. 【bzoj3291】Alice与能源计划 模拟费用流+二分图最大匹配

    题目描述 在梦境中,Alice来到了火星.不知为何,转眼间Alice被任命为火星能源部长,并立刻面临着一个严峻的考验. 为了方便,我们可以将火星抽象成平面,并建立平面直角坐标系.火星上一共有N个居民点 ...

  8. 贪心(模拟费用流):NOIP2011 观光公交

    [问题描述] 风景迷人的小城Y 市,拥有n 个美丽的景点.由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供更便捷的交通服务.观光公交车在第0 分钟出现在1号景点,随后依次前往2. ...

  9. BZOJ4977[Lydsy1708月赛]跳伞求生——贪心+堆+模拟费用流

    题目链接: 跳伞求生 可以将题目转化成数轴上有$n$个人和$m$个房子,坐标分别为$a_{i}$和$b_{i}$,每个人可以进一个他左边的房子,每个房子只能进一个人.每个房子有一个收益$c_{i}$, ...

随机推荐

  1. Oracle调用Java类开发的存储过程、函数的方法

    oracle调用java类的基本步骤 1. 编写java代码,后续可以直接使用java代码,class文件或者jar包 2. 将写好的java代码导入到oracle数据库中,有两种方法:一种是使用lo ...

  2. JAVA 水题

    纯粹是让我来掌握熟练度的. 1.金蝉素数 某古寺的一块石碑上依稀刻有一些神秘的自然数. 专家研究发现:这些数是由1,3,5,7,9 这5 个奇数字排列组成的5 位素数,且同时去掉它的最高位与最低位数字 ...

  3. GO语言学习(十七)Go 语言类型转换

    Go 语言类型转换 类型转换用于将一种数据类型的变量转换为另外一种类型的变量.Go 语言类型转换基本格式如下: type_name(expression) type_name 为类型,expressi ...

  4. jquery的滚动事件

    $(selector).scroll(function);当滚动到合适的条件下,就触发某个函数. 现在基本就是前端利用AJAX对数据进行拼接操作,渲染进html的DOM结构中.

  5. jQuery的实现原理和核心

    1.jQuery的实现原理 1)jQuery采用的是构造函数模式进行开发的,jQuery是一个类 2)上面说的常用的方法(CSS.属性.筛选.事件.动画.文档处理)都是定义在jQuery.protot ...

  6. vue中监听路由参数变化

    今天遇到一个这样的业务场景:在同一个路由下,只改变路由后面的参数值, 比如在这个页面  /aaa?id=1 ,在这个页面中点击一个按钮后 跳转到 /aaa?id=2 , 但从“/aaa?id=1”到“ ...

  7. Maven使用yuicompressor-maven-plugin打包压缩css、js文件

    最近项目想使用在maven打包的时间压缩js,css文件,采用yuicompressor-maven-plugin插件进行压缩,但只是压缩减小大小,提高请求速度,并没有对js进行混淆.下面就写一下这个 ...

  8. C#自定义配置文件节的实现

    1.配置文件:(注意configSections必须放在最上面否则会报错) <?xml version="1.0" encoding="utf-8" ?& ...

  9. Learn from Architects of Buildings

     Learn from Architects of Buildings Keith Braithwaite Architecture is a social act and the material ...

  10. POJ 1384 Piggy-Bank (ZOJ 2014 Piggy-Bank) 完全背包

    POJ :http://poj.org/problem?id=1384 ZOJ:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode ...