NOIP模拟(10.19)T3 放盒子

放盒子

题目背景:

10.19 NOIP模拟T3

分析:费用流

这个题,我是真的没有往费用流想······

考场上还出了点问题,明明应该写双关键字排序的····然后我只排了一个关键词····明明有50分的暴力的,挂成了15分······悲剧,下次一定要注意,怎么错都轻松过样例······

这个题,考虑怎么办,显然我们对于每一个盒子要看第一,是否有盒子可以装他,第二,是否可以装下其他盒子,第三,装哪一个盒子,第四,哪一个盒子装它,每一个盒子只能用一次,有没有感觉到什么2333,我们对于每个盒子拆成两个点,为x1, x2,如果对于两个盒子,x, y, x可以装下y盒子,那么我们从x1y2连边,流量为1,费用为y盒子的面积(注意是y,就是y),然后从S向所有的第一部分点连边,流量为1,费用为0,从所有第二部分点向T连边,流量为1,费用为0,然后跑一遍最大费用最大流,用总的盒子的面积减去最大费用即可,流量限制满足每个盒子只用一次,选中了的盒子表示它可以被套住,减去费用,正确性合理。

Source

/*
	created by scarlyw
*/
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <cctype>
#include <vector>
#include <queue>
#include <map>
#include <set>

inline char read() {
	static const int IN_LEN = 1024 * 1024;
	static char buf[IN_LEN], *s, *t;
	if (s == t) {
		t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
		if (s == t) return -1;
	}
	return *s++;
}

/*
template<class T>
inline void R(T &x) {
	static bool iosig;
	static char c;
	for (iosig = false, c = read(); !isdigit(c); c = read()) {
		if (c == -1) return ;
		if (c == '-') iosig = true;
	}
	for (x = 0; isdigit(c); c = read()) x = ((x << 2) + x << 1);
	if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;
inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}

template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
	fwrite(obuf, 1, oh - obuf, stdout);
}

///*
template<class T>
inline void R(T &x) {
	static bool iosig;
	static char c;
	for (iosig = false, c = getchar(); !isdigit(c); c = getchar()) {
		if (c == -1) return ;
		if (c == '-') iosig = true;
	}
	for (x = 0; isdigit(c); c = getchar()) x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int MAXN = 400 + 10;
const int INF = ~0u >> 2;

int n, final = ~0u >> 1;

struct data {
	int l, w;
	inline bool operator < (const data &a) const {
		return (l == a.l) ? (w < a.w) : (l < a.l);
	}
} box[MAXN];

struct node {
	int to, w, c, rev;
	node(int to = 0, int w = 0, int c = 0, int rev = 0) : to(to), w(w), c(c), 
		rev(rev) {}
} ;

bool vis[MAXN];

int ans, s ,t, cnt, sum;
std::vector<node> edge[MAXN];

inline void add_edge(int x, int y, int w, int c) {
	edge[x].push_back(node(y, w, c, edge[y].size()));
	edge[y].push_back(node(x, 0, -c, edge[x].size() - 1));
}

inline void build_graph() {
	R(n), cnt = 0;
	for (int i = 1; i <= n; ++i) R(box[i].l), R(box[i].w);
	std::sort(box + 1, box + n + 1);
	for (int i = 1; i <= n; ++i) 
		if (box[i].l != box[i - 1].l || box[i].w != box[i - 1].w)
			box[++cnt] = box[i], ans += box[i].l * box[i].w;
	s = 0, t = 2 * cnt + 1;
	for (int i = 1; i <= cnt; ++i)
		for (int j = 1; j < i; ++j)
			if (box[j].w <= box[i].w)
				add_edge(i, j + cnt, 1, box[j].l * box[j].w);
	for (int i = 1; i <= cnt; ++i) 
		add_edge(s, i, 1, 0), add_edge(i + cnt, t, 1, 0);
}

inline bool spfa_slf(int s, int t) {
	static bool vis[MAXN];
	static int dis[MAXN];
	static std::deque<int> q;
	for (int i = s; i <= t; ++i) vis[i] = false, dis[i] = -INF;
	q.push_back(t), dis[t] = 0, vis[t] = true;
	while (!q.empty()) {
		int cur = q.front();
		q.pop_front(), vis[cur] = false;
		for (int p = 0; p < edge[cur].size(); ++p) {
			node *e = &edge[cur][p];
			if (edge[e->to][e->rev].w > 0 && dis[e->to] < dis[cur] - e->c) {
				dis[e->to] = dis[cur] - e->c;
				if (!vis[e->to]) {
					if (!q.empty() && dis[e->to] > dis[q.front()]) 
						q.push_front(e->to), vis[e->to] = true;
					else q.push_back(e->to), vis[e->to] = true;
				}
			}
		}
	}
	for (int i = s; i <= t; ++i)
		for (int p = 0; p < edge[i].size(); ++p) {
			node *e = &edge[i][p];
			e->c += dis[e->to] - dis[i];
		}
	return sum += dis[s], (dis[s] > -INF);
}

inline int dfs(int cur, int flow, int t) {
	if (cur == t) return ans -= sum * flow, flow;
	int ret = 0;
	vis[cur] = true;
	for (int p = 0; p < edge[cur].size(); ++p) {
		node *e = &edge[cur][p];
		if (e->w > 0 && e->c == 0 && !vis[e->to]) {
			int f = dfs(e->to, std::min(flow - ret, e->w), t);
			ret += f, e->w -= f, edge[e->to][e->rev].w += f;
			if (ret == flow) return flow;
		}
	}
	return ret;
}

inline void cost_flow(int s, int t) {
	while (spfa_slf(s, t)) {
		do memset(vis, false, sizeof(bool) * (t + 5));
		while (dfs(s, INF, t));
	}
	std::cout << ans;
}

int main() {
//	freopen("box.in", "r", stdin);
//	freopen("box.out", "w", stdout);
	build_graph();
	cost_flow(s, t);
	return 0;
}


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值