solved 1/13

2016 Multi-University Training Contest 9

二分+最大权闭合图 Less Time, More profit(BH)

题意就是有n个工厂,m个商店 
每个工厂有建造时间ti,花费payi 
每个商店和k个工厂有关,如果这k个工厂都建造了,那么能获利proi 
问你求收益(∑pro−∑pay)≥L时,首先满足时间t最小,其次是收益p最大

首先二分时间的答案,然后看那些工厂能建造,然后工厂是花费,商店是收益,并且要与商店有关的工厂都建造了,才能获利,所以这是一个最大权闭合图的问题。

关于最大权闭合图:岐哥的博客

闭合图就是闭合图中的点的后继也在这个闭合图中。而闭合图是反映事物间必要条件的关系的,也就是说一个点是它后继的必要条件。也就是说要有这个点,它的后继点也要都存在。

最大权闭合图:

建图:构造一个源点S,汇点T。我们将S与所有权值为正的点连一条容量为其权值的边,将所有权值为负的点与T连一条容量为其权值的绝对值的边,原来的边将其容量定为正无穷。

求解:最大权闭合图=正的点权和-最小割=正的点权和-最大流。

时间复杂度为.

代码:

#include <bits/stdc++.h>

const int N = 200 + 5;
const int INF = 0x3f3f3f3f;
int pay[N], t[N];
int pro[N];
std::vector<int> need[N];
int n, m;
int L; /*
*最大流之Dinic算法:不停地构造层次图,然后用阻塞流增广。
*时间复杂度为 O(n^2*m)。
*如果容量为1,复杂度为 O(min(n^(2/3), m^(1/2)*m)。
*对于二分图最大匹配这样的特殊图,复杂度为 O(n^(1/2)*m)
*/
struct Max_Flow {
struct Edge {
int from, to, cap, flow;
};
std::vector<Edge> edges;
std::vector<int> G[2*N]; //保存每个结点的弧在edges里的序号
int level[2*N], cur[2*N]; //结点在层次图中的等级。结点当前弧下标。
int n, m, s, t;
//初始化顶点个数n,边的个数m在加边时统计,s和t分别为源点和汇点
void init(int n) {
this->n = n;
for (int i=0; i<=n; ++i) {
G[i].clear ();
}
edges.clear ();
}
void add_edge(int from, int to, int cap) {
edges.push_back ((Edge) {from, to, cap, 0});
edges.push_back ((Edge) {to, from, 0, 0});
m = edges.size ();
G[from].push_back (m - 2);
G[to].push_back (m - 1);
}
bool BFS() {
std::fill (level, level+1+n, -1);
std::queue<int> que;
level[s] = 0; que.push (s);
while (!que.empty ()) {
int u = que.front (); que.pop ();
for (int i=0; i<G[u].size (); ++i) {
Edge &e = edges[G[u][i]];
if (level[e.to] == -1 && e.cap > e.flow) {
level[e.to] = level[u] + 1;
que.push (e.to);
}
}
}
return level[t] != -1;
}
int DFS(int u, int a) {
if (u == t || a == 0) {
return a; //a表示当前为止所有弧的最小残量
}
int flow = 0, f;
for (int &i=cur[u]; i<G[u].size (); ++i) {
Edge &e = edges[G[u][i]];
if (level[u] + 1 == level[e.to]
&& (f = DFS (e.to, std::min (a, e.cap - e.flow))) > 0) {
e.flow += f;
edges[G[u][i]^1].flow -= f;
flow += f; a -= f;
if (a == 0) {
break;
}
}
}
return flow;
}
int Dinic(int s, int t) {
this->s = s; this->t = t;
int flow = 0;
while (BFS ()) {
std::fill (cur, cur+1+n, 0);
flow += DFS (s, INF);
}
return flow;
}
}max_flow; int check(int max_t) {
int S = 0, T = n + m + 1;
int sum = 0;
max_flow.init (n+m+2);
for (int i=1; i<=m; ++i) {
max_flow.add_edge (S, i, pro[i]);
bool flag = true;
for (int j: need[i]) {
if (t[j] > max_t) {
flag = false;
break;
}
}
if (flag) {
for (int j: need[i]) {
max_flow.add_edge (i, m+j, INF);
}
sum += pro[i];
}
}
for (int i=1; i<=n; ++i) {
if (t[i] <= max_t)
max_flow.add_edge (m+i, T, pay[i]); //abs (-pay[i])
}
int min_cut = max_flow.Dinic (S, T);
if (sum - min_cut >= L)
return sum - min_cut;
else
return -1;
} void solve(int cas) {
printf ("Case #%d: ", cas);
int best_t = INF, best_p = 0;
int l = 1, r = 1000000000;
while (l <= r) {
int mid = l + r >> 1;
int res = check (mid);
if (res != -1) {
best_t = std::min (best_t, mid);
best_p = res;
r = mid - 1;
} else
l = mid + 1;
}
if (best_t < INF)
printf ("%d %d\n", best_t, best_p);
else
puts ("impossible");
} int main() {
int T;
scanf ("%d", &T);
for (int cas=1; cas<=T; ++cas) {
scanf ("%d%d%d", &n, &m, &L);
for (int i=1; i<=n; ++i) {
scanf ("%d%d", pay+i, t+i);
}
for (int i=1; i<=m; ++i) {
scanf ("%d", pro+i);
need[i].clear ();
int k;
scanf ("%d", &k);
while (k--) {
int id;
scanf ("%d", &id);
need[i].push_back (id);
}
}
solve (cas);
}
return 0;
}

还有贪心的做法,时间复杂度解释

代码:

#include <bits/stdc++.h>

const int N = 200 + 5;
const int INF = 0x3f3f3f3f; struct Plant {
int pay, t;
}p[N];
std::vector<int> id[N]; struct Shop {
int pro;
std::vector<int> need;
int pay;
int max_t;
int done;
}s[N]; int n, m;
int L; bool vis_p[N], vis_s[N]; int check(int max_t) {
memset (vis_p, false, sizeof (vis_p));
memset (vis_s, false, sizeof (vis_s));
for (int i=0; i<m; ++i)
s[i].done = 0;
int ret = -INF, tmp = 0;
for (; ;) {
int max_val = -INF, k = -1;
for (int i=0; i<m; ++i) {
if (!vis_s[i] && s[i].max_t <= max_t) {
if (max_val < s[i].pro - s[i].pay + s[i].done) {
max_val = s[i].pro - s[i].pay + s[i].done;
k = i;
}
}
}
if (max_val == -INF)
break;
vis_s[k] = true; //max m times
tmp += max_val;
ret = std::max (ret, tmp);
for (int j: s[k].need) {
if (!vis_p[j]) {
vis_p[j] = true;
for (int l: id[j]) {
if (!vis_s[l]) {
s[l].done += p[j].pay;
}
}
}
}
}
return ret >= L ? ret : -1;
} void solve(int cas) {
printf ("Case #%d: ", cas);
int best_t = INF, best_p = 0;
int l = 1, r = 1000000000;
while (l <= r) {
int mid = l + r >> 1;
int res = check (mid);
if (res != -1) {
best_t = std::min (best_t, mid);
best_p = res;
r = mid - 1;
} else
l = mid + 1;
}
if (best_t < INF)
printf ("%d %d\n", best_t, best_p);
else
puts ("impossible");
} int main() {
int T;
scanf ("%d", &T);
for (int cas=1; cas<=T; ++cas) {
scanf ("%d%d%d", &n, &m, &L);
for (int i=0; i<n; ++i) {
scanf ("%d%d", &p[i].pay, &p[i].t);
id[i].clear ();
}
for (int i=0; i<m; ++i) {
scanf ("%d", &s[i].pro);
s[i].need.clear ();
s[i].max_t = -1;
s[i].pay = 0;
int k;
scanf ("%d", &k);
while (k--) {
int j;
scanf ("%d", &j);
j--;
if (p[j].t > s[i].max_t)
s[i].max_t = p[j].t;
s[i].pay += p[j].pay;
s[i].need.push_back (j);
id[j].push_back (i);
}
}
solve (cas);
}
return 0;
}

  

2016 Multi-University Training Contest 9的更多相关文章

  1. 2016 Al-Baath University Training Camp Contest-1

    2016 Al-Baath University Training Camp Contest-1 A题:http://codeforces.com/gym/101028/problem/A 题意:比赛 ...

  2. 2016 Al-Baath University Training Camp Contest-1 E

    Description ACM-SCPC-2017 is approaching every university is trying to do its best in order to be th ...

  3. 2016 Al-Baath University Training Camp Contest-1 A

    Description Tourist likes competitive programming and he has his own Codeforces account. He particip ...

  4. 2016 Al-Baath University Training Camp Contest-1 J

    Description X is fighting beasts in the forest, in order to have a better chance to survive he's gon ...

  5. 2016 Al-Baath University Training Camp Contest-1 I

    Description It is raining again! Youssef really forgot that there is a chance of rain in March, so h ...

  6. 2016 Al-Baath University Training Camp Contest-1 H

     Description You've possibly heard about 'The Endless River'. However, if not, we are introducing it ...

  7. 2016 Al-Baath University Training Camp Contest-1 G

    Description The forces of evil are about to disappear since our hero is now on top on the tower of e ...

  8. 2016 Al-Baath University Training Camp Contest-1 F

    Description Zaid has two words, a of length between 4 and 1000 and b of length 4 exactly. The word a ...

  9. 2016 Al-Baath University Training Camp Contest-1 D

    Description X is well known artist, no one knows the secrete behind the beautiful paintings of X exc ...

  10. 2016 Al-Baath University Training Camp Contest-1 C

    Description Rami went back from school and he had an easy homework about bitwise operations (and,or, ...

随机推荐

  1. 多线程 or 多进程 (转强力推荐)

    在Unix上编程采用多线程还是多进程的争执由来已久,这种争执最常见到在C/S通讯中服务端并发技术 的选型上,比如WEB服务器技术中,Apache是采用多进程的(perfork模式,每客户连接对应一个进 ...

  2. Google Chrome浏览器调试入门————转载只为自己查看方便

    Google Chrome浏览器调试 作为Web开发人员,我为什么喜欢Google Chrome浏览器 [原文地址:http://www.cnblogs.com/QLeelulu/archive/20 ...

  3. haartraining生成.xml过程

    继续向大神学习http://www.cnblogs.com/tornadomeet/archive/2012/03/28/2420936.html

  4. DataSnap 用TStream 传递大数据 返回流大小为-1的情况

    DataSnap可以直接传递和返回TStream类型的参数,这点是很方便的.但是很多人发现好像大小稍微大点就工作不正常了,就变相使用其它类型转换来转换去,这样便利性就失去了. 官方有篇博客很详细的介绍 ...

  5. Linux 实现rsyslog日志里面的IP地址记录 未测试

    之前我是在bashrc中添加了一句,让系统操作日志时向rsyslog发送一份内容,现在只要在发送的时候,自己再获取下当前的远程登录IP加进去就可以,像这样 /etc/bashrc sshClientI ...

  6. 新浪网易淘宝等IP地区信息查询开放API接口调用方法

    通过IP地址获取对应的地区信息通常有两种方法:1)自己写程序,解析IP对应的地区信息,需要数据库.2)根据第三方提供的API查询获取地区信息. 第一种方法,参见文本<通过纯真IP数据库获取IP地 ...

  7. 【消息队列MQ】各类MQ比较

    目录(?)[-] RabbitMQ Redis ZeroMQ ActiveMQ JafkaKafka 目前业界有很多MQ产品,我们作如下对比: RabbitMQ 是使用Erlang编写的一个开源的消息 ...

  8. 利用WinHEX,重构狂牛加密视频1.0.0.1【只适合RIFF(AVI)】

    幸亏是视频部分没有进行加密 1.用 WinHEX 打开狂牛加密视频, 查找 [RIFF] 字符串 2.光标放在 RIFF的 [R]上面, 按 CTRL+SHIFT+END 3.把选择的块写入新文件 H ...

  9. Myeclipse 安装svn插件

    安装subclipse,  SVN插件1.从官网下载site-1.8.22.zip文件  访问不了可点我网盘2.从中解压出features与 plugins文件夹,复制到MyEclipse\MyEcl ...

  10. HttpHandler动态生成图片

    1.向服务器请求返回图片,浏览器是不知道服务上有这个图片的存在的,只是发出请求,接收请求,显示图片 string path = context.Server.MapPath("~/1.jpg ...