趁着竞赛课,写一波笔记。。。。
不然就忘了为什么上下界网络流和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();
}
}