有上下界网络流 ---- Zoj3229 Shoot the Bullet|东方文花帖|【模板】有源汇上下界最大流

学习资料+题目链接

题目大意:

在这里插入图片描述


模板讲解

#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = N;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x) {
   x = 0;char ch = getchar();ll f = 1;
   while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
   while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)  {
   read(first);
   read(args...);
}
struct node {
   int to, next, len; 
}e[maxn];
int head[maxn], cnt;
int n, m, s, t;
inline void add(int from, int to, int len) {
   e[cnt] = {to,head[from],len};
   head[from] = cnt ++;
   e[cnt] = {from,head[to],0};
   head[to] = cnt ++;
}

int d[maxn],cur[maxn];
int pre[maxn], flow[maxn];

bool bfs() {
   ms(d,0);
   queue<int> q;
   q.push(s); d[s] = 1;
   while(!q.empty()) {
      int u = q.front(); q.pop();
      for(int i = head[u]; ~i; i = e[i].next) {
         int v = e[i].to;
         if(d[v] || e[i].len <= 0) continue;
         q.push(v);
         d[v] = d[u] + 1;
      }

   }      
   for(int i = 0; i <= t; ++ i) cur[i] = head[i];
   return d[t] != 0;
}

int dfs(int u, int flow) {
    if(u == t) return flow;
    for(int &i = cur[u]; ~i; i = e[i].next) {
        int v = e[i].to;
        if(d[u] + 1 != d[v] || e[i].len <= 0) continue;
        int delta = dfs(v,min(flow,e[i].len));
        if(delta <= 0) continue;
        e[i].len -= delta;
        e[i^1].len += delta;
        return delta;
    }
    return 0;
}

int get_maxflow() {
    int maxFlow = 0, delta;
    while(bfs())//bfs进行构建最短路网络
         while(delta = dfs(s,INF))
             maxFlow += delta;
    return maxFlow;
}
//......................
int Tn, Tm, Gx[maxn], in[maxn], out[maxn];
// 对于原图的所有的点(包括原图的源点和汇点)求一个流入量in和一个流出量out
// 对于in需求量大的,我们新建一个源点(和原图不一样)去补充差值。
// 对于out需求量大的,我们新建式一个汇点去补充差值
// in和out数组是加状态的下界
// 而且第一遍跑出来的可行流是e[cnt-1].len,不是maxflow
// 第二遍从原图的源点到汇点的才是maxflow
void init() {
	ms(in,0), ms(out,0), ms(head,-1);
	cnt = 0;
}
int main() {
    IOS;
    while(cin >> Tn >> Tm) {
    	init();
    	for(int i = 1; i <= Tm; ++ i) cin >> Gx[i];
    	int s1 = Tn+Tm+1, t1 = Tn+Tm+2, s2 = Tn+Tm+3, t2 = Tn+Tm+4;
		// s1和t1是原图的源点和汇点
		// s2和t2是无源汇上下界网络流的源点和汇点
		int C, D;
		for(int i = 1; i <= Tn; ++ i) {
			cin >> C >> D;
			int T, L, R;
			add(s1,i,D);
			in[i] += 0;
			in[s1] += 0;
			for(int j = 1; j <= C; ++ j) {
				cin >> T >> L >> R;
				T ++;
				in[T+Tn] += L, out[i] += L;
				add(i,T+Tn,R-L); 				
			}
		} 
		for(int i = 1; i <= Tm; ++ i) {
			in[t1] += Gx[i], out[i+Tn] += Gx[i];
			add(i+Tn,t1,INF-Gx[i]);
		}
		int sum = 0;
		for(int i = 1; i <= Tn+Tm+2; ++ i) {
			if(in[i] > out[i]) 
			   add(s2,i,in[i]-out[i]), sum += (in[i]-out[i]);
			else add(i,t2,out[i]-in[i]);
		}
		add(t1,s1,INF);
		s = s2, t = t2;
		if(get_maxflow()!=sum) cout << "-1\n\n";
		else {
		   int flow1 = e[cnt-1].len;// 注意!!!
		   s = s1, t = t1;
		   e[cnt-1].len = 0;
		   e[cnt-2].len = 0;// 原图源点向汇点连的边
		   cout << flow1 + get_maxflow() << "\n\n";
		}
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值