kebab - 网络流最大流 + 区间离散化
Posted emcikem
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了kebab - 网络流最大流 + 区间离散化相关的知识,希望对你有一定的参考价值。
传送门
和我上一篇博客的思路很像,区别在于每一个任务的(s_i,e_i)不一样,这题的(e_i - s_i)很大,所以无法直接全部进行建立
那么考虑对其进行离散化,也就是或对于区间[l,r]的作为一个结点,然后按照前面的方法去建立
对于第一层边的建立,容量就是烤肉数 * 单个烤肉的时间
第二层边的建立,对应的应该是(times[i] - times[i - 1] * m),其中(times)数组是离散化后的时间点,那么容量是时间段 * m
第三层边的建立,和第二层边一样
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 2000 + 5;
int n, m, s, t;
struct Edge{
int to, next, w;
}e[N * N];
int head[N], tot = 1, cur[N]; //弧优化
void add(int u, int v, int w){
e[++tot].to = v;
e[tot].w = w;
e[tot].next = head[u];
head[u] = tot;
}
int dis[N];
int dfs(int u, int flow){ //保证了每次DFS都能找到增广路
if(u == t) return flow;
int sum = 0;
for(int i = cur[u]; i && flow > 0; i = e[i].next){
cur[u] = i;
int v = e[i].to, w = e[i].w;
if(w > 0 && dis[v] == dis[u] + 1){
int t = dfs(v, min(flow, w)); //获取这条增广路的最小流量
e[i].w -= t; e[i ^ 1].w += t; //减去最小流量,同时反向边加上最小流量
flow -= t; sum += t;
}
}
if(!sum) dis[u] = 0;//结果u无法到达终点,或者没有增广路,切断经过这个点的路径
return sum;
}
bool bfs(){//分层判断是否有增广路
memset(dis, 0, sizeof(dis));
queue<int> q;
q.push(s); dis[s] = 1; cur[s] = head[s];//弧优化
while(!q.empty()){
int u = q.front(); q.pop();
for(int i = head[u]; i; i = e[i].next){
int v = e[i].to, w = e[i].w;
if(w > 0 && !dis[v]) {
cur[v] = head[v];// v这个点从head[v]出发是可行的
dis[v] = dis[u] + 1;//分层
q.push(v);
if(v == t) return 1;//已经到达增广路,直接返回
}
}
}
return dis[t];
}
ll Dinic(){
ll max_flow = 0;
while(bfs()){
max_flow += dfs(s, 2e9);
}
return max_flow;
}
int st[N], ed[N], num[N], ti[N], times[N], k = 0;
int main(){
int n, m;
while(~scanf("%d%d", &n, &m)){
memset(head, 0, sizeof(head));
tot = 1;
k = 0;
ll sum = 0;
for(int i = 1; i <= n; i++){
scanf("%d%d%d%d", &st[i], &num[i], &ed[i], &ti[i]);
times[++k] = st[i];
times[++k] = ed[i];
sum += num[i] * ti[i];
}
sort(times + 1, times + k + 1);
k = unique(times + 1, times + k + 1) - times;//离散化
s = 0, t = n + k + 1;
for(int i = 1; i <= n; i++){//第一层边
add(s, i, num[i] * ti[i]);
add(i, s, 0);
}
for(int i = 1; i <= n; i++){//第二层边
for(int j = 1; j <= k; j++){
if(st[i] <= times[j - 1] && times[j] <= ed[i]){
add(i, n + j, 2e9);
add(n + j, i, 0);
}
}
}
for(int i = 1; i <= k; i++){// 第三层边
add(n + i, t, (times[i] - times[i - 1]) * m);
add(t, n + i, 0);
}
printf("%s
", Dinic() == sum ? "Yes" : "No");
}
return 0;
}
以上是关于kebab - 网络流最大流 + 区间离散化的主要内容,如果未能解决你的问题,请参考以下文章
poj3680 Intervals 区间k覆盖问题 最小费用最大流 建图巧妙
POJ2047 Concert Hall Scheduling(最小费用最大流)
POJ3680:Intervals(离散化+最大流最小费用)
ACM-ICPC 2018 焦作赛区网络预赛 F. Modular Production Line (区间K覆盖-最小费用流)