动态动态规划DDP + 上下界网络流学习笔记。。。。。

趁着竞赛课,写一波笔记。。。。
不然就忘了为什么上下界网络流和ddp我只花了1个小时就学会了???我胡一个月怎么办

其实这个ddp很假。。。

把矩乘改成去极值的形式
然后这个东西满足结合律-----》启发我们套用线段树实现动态维护


然后有些题会让你在树上进行操作。。。

直接LCT或者树链po分就好了


上下界网络流也很假
分了4种情况
1.无汇源的上下界可行流
2.有汇源上下界可行流
3.有汇源的上下界最大流
4.有汇源上下界最小流

其实本质就第一种
无汇源的上下界可行流

直接在残余网络建虚拟节点。。然后跑满流就好了

一定是满足流量守恒
证明先鸽了

2.直接连s----t(下界0 上界无穷)

3,4.跑可行流后在残余网络跑最小最大流

注意:
原图的边 要在新图里面连上上下界差值
大致乱写了一下的1.

#include<bits/stdc++.h>
#define MAXN 1005
using namespace std;

int T,maxl;
int n,m,s,t;
int h[MAXN],tot,cc[MAXN],jl[225][225];
int dep[MAXN],vis[MAXN],gg,cur[MAXN];

struct node{
	int from,to,next,rest,down,up;
}e[MAXN << 1],e2[MAXN << 1];//´¢´æн¨µÄ±ß  ÒÔ¼°  Ô­À´ÍøÂçµÄ  

void add(int x , int y , int z){
	tot++;
	e[tot].from = x;
	e[tot].to = y;
	e[tot].rest = z;
	e[tot].next = h[x];
	h[x] = tot;
}

int bfs(){
	memset(vis , -1 , sizeof(vis));
	memset(dep , 0x3f , sizeof(dep));
	for(int i = 1 ; i <= n + 5 ; i++)cur[i] = h[i];
	queue<int>q;q.push(s);vis[s] = 1;dep[s] = 0;
	int now;
	while(!q.empty()){
		now = q.front();q.pop();vis[now] = (-1);
		for(int i = h[now] ; i != (-1) ; i = e[i].next){
			if(dep[e[i].to] > dep[now] + 1 && e[i].rest){
				dep[e[i].to] = dep[now] + 1;
				if(vis[e[i].to] == (-1)){
					vis[e[i].to] = 1;
					q.push(e[i].to);
				}
			}
		}
	}
	if(dep[t] > 9999999)return 0;
	else return 1;
}

int dfs(int now , int low){
	if(now == t){
		maxl += low;
		gg = 1;
		return low;
	}
	int res,used = 0;
	for(int i = cur[now] ; i != (-1) ; i = e[i].next){
		cur[now] = i;
		if(e[i].rest && dep[e[i].to] == dep[now] + 1){
			if(res = dfs(e[i].to , min(low , e[i].rest))){
				used += res;
				e[i].rest -= res;
				e[i ^ 1].rest += res;
				if(used == low)break;
			}
		}
	}
	return used;
}

void dinic(){
	maxl = 0;
	while(bfs()){
		gg = 1;
		while(gg){
			gg = 0;
			dfs(s , 99999999);
		}
	}
	cout<<maxl<<endl;
}

void init(){
	memset(jl , 0 , sizeof(jl));
	memset(cc , 0 , sizeof(cc));
	memset(h , -1 , sizeof(h));
	tot = (-1);
	cin>>n>>m;
	for(int i = 1 ; i <= m ; i++){
		cin>>e2[i].from>>e2[i].to>>e2[i].down>>e2[i].up;
		cc[e2[i].to] += e2[i].down , cc[e2[i].from] -= e2[i].down;
		add(e2[i].from , e2[i].to , e2[i].up - e2[i].down);
		add(e2[i].to , e2[i].from , 0);	
	}
	s = n + 1 , t = n + 2;
	for(int i = 1 ; i <= n ; i++){
		if(cc[i] > 0){//¶àÁ˽øÀ´µÄ   Òª¸ø½øÀ´µÄÕÒ¸ö³ö´¦ 
			add(s , i , cc[i]);
			add(i , s , 0);
		}
		else if(cc[i] < 0){//¶àÁ˳öÈ¥µÄ   Òª¸ø³öÈ¥µÄÕÒ¸öÔ­Òò 
			add(i , t , -cc[i]);
			add(t , i , 0);
		}
	}
	dinic();
	for(int i = 0 ; i <= tot ; i++)jl[e[i].from][e[i].to] += e[i ^ 1].rest;
	int panduan = 0;
	memset(cc , 0 , sizeof(cc));
	for(int i = 1 ; i <= m ; i++){
		 if(e[i].down + jl[e[i].from][e[i].to] > e[i].up)panduan = 1;
		 cc[e2[i].to] += e2[i].down , cc[e2[i].from] -= e2[i].down;
	}
	for(int i = 1 ; i <= n ; i++)if(cc[i])panduan = 1;
	if(panduan)cout<<"No"<<endl;
	for(int i = 1 ; i <= m ; i++)cout<<e[i].down + jl[e[i].from][e[i].to]<<endl;
}

int main(){
	cin>>T;
	while(T--){
		init();
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值