8.11 暑假集训——网络流篇

来源:互联网 发布:淘宝名字怎么改昵称 编辑:程序博客网 时间:2024/05/16 10:56

第一次接触网络流,还不习惯用这种很大块而且不知道内部原理的“模板”,熟悉花了挺长时间,勉强算是会用了吧
对最大流,最省费用最大流的意义还需要加深理解,可以多复习一下最后一题,然后,刷题–

前两道是模板题
Flow problem

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <algorithm>using namespace std;#define type int  //type类型可以是long long,int,double#define maxn 25  //点数#define maxm 2005 //边数,注意大于最小边数的两倍#define INF 1e8  //1e8,1e9都可int n,m;int s, t;struct Edge {    int from, to, next;    type cap, flow;    void get (int u, int a, int b, type c, type d) {        from = u; to = a; next = b; cap = c; flow = d;    }}edge[maxm];int tol;int head[maxn];int gap[maxn], dep[maxn], pre[maxn], cur[maxn];void init () {    tol = 0;    memset (head, -1, sizeof head);}void add_edge (int u, int v, type w, type rw=0) {  //模板加边    edge[tol].get(u, v,head[u],w,0);head[u]=tol++;    edge[tol].get(v, u,head[v],rw,0);head[v]=tol++;}type sap (int start, int eend, int N) {  //sap求最大流    memset (gap, 0, sizeof gap);    memset (dep, 0, sizeof dep);    memcpy (cur, head, sizeof head);    int u = start;    pre[u] = -1;    gap[0] = N;    type ans = 0;    while (dep[start] < N) {        if (u == eend) {            type Min = INF;            for (int i = pre[u]; i != -1; i = pre[edge[i^1].to])                if (Min > edge[i].cap - edge[i].flow)                   Min = edge[i].cap-edge[i].flow;            for (int i = pre[u]; i != -1; i = pre[edge[i^1].to]) {                edge[i].flow += Min;                edge[i^1].flow -= Min;            }            u = start;            ans += Min;            continue;        }        bool flag = false;        int v;        for (int i = cur[u]; i != -1; i = edge[i].next) {            v = edge[i].to;            if (edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]) {                flag = true;                cur[u] = pre[v] = i;                break;            }        }        if (flag) {            u = v;            continue;        }        int Min = N;        for (int i = head[u]; i != -1; i = edge[i].next)            if (edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) {                  Min = dep[edge[i].to];                  cur[u] = i;             }        gap[dep[u]]--;        if (!gap[dep[u]]) return ans;        dep[u] = Min+1;        gap[dep[u]]++;        if (u != start) u = edge[pre[u]^1].to;    }    return ans;}int main(){    int tt;   //这里的案例数注意不能用习惯的t,会隐藏全局变量    int cas=1;    scanf("%d",&tt);    while(tt--){        init();   //每次初始化        cin>>n>>m;        for(int i=0;i<m;i++){            int u,v,w;            cin>>u>>v>>w;            add_edge(u,v,w); //调用模板一        }        s=1,t=n;  //要给全局变量s,t,n赋值        int ans=sap(1,n,n);  //调用二        printf("Case %d: %d\n",cas++,ans);    }    return 0;}

Drainage Ditches

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <algorithm>using namespace std;const int maxn=405;const int maxm=405;const int INF=2e9+2e6;#define type intint n;int s, t;struct Edge {    int from, to, next;    type cap, flow;    void get (int u, int a, int b, type c, type d) {        from = u; to = a; next = b; cap = c; flow = d;    }}edge[maxm];int tol;int head[maxn];int gap[maxn], dep[maxn], pre[maxn], cur[maxn];void init () {    tol = 0;    memset (head, -1, sizeof head);}void add_edge (int u, int v, type w, type rw=0) {    //cout << u << " " << v << " " << w << endl;    edge[tol].get(u, v,head[u],w,0);head[u]=tol++;    edge[tol].get(v, u,head[v],rw,0);head[v]=tol++;}type sap (int start, int end, int N) {    memset (gap, 0, sizeof gap);    memset (dep, 0, sizeof dep);    memcpy (cur, head, sizeof head);    int u = start;    pre[u] = -1;    gap[0] = N;    type ans = 0;    while (dep[start] < N) {        if (u == end) {            type Min = INF;            for (int i = pre[u]; i != -1; i = pre[edge[i^1].to])                if (Min > edge[i].cap - edge[i].flow)                   Min = edge[i].cap-edge[i].flow;            for (int i = pre[u]; i != -1; i = pre[edge[i^1].to]) {                edge[i].flow += Min;                edge[i^1].flow -= Min;            }            u = start;            ans += Min;            continue;        }        bool flag = false;        int v;        for (int i = cur[u]; i != -1; i = edge[i].next) {            v = edge[i].to;            if (edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]) {                flag = true;                cur[u] = pre[v] = i;                break;            }        }        if (flag) {            u = v;            continue;        }        int Min = N;        for (int i = head[u]; i != -1; i = edge[i].next)            if (edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) {                  Min = dep[edge[i].to];                  cur[u] = i;             }        gap[dep[u]]--;        if (!gap[dep[u]]) return ans;        dep[u] = Min+1;        gap[dep[u]]++;        if (u != start) u = edge[pre[u]^1].to;    }    return ans;}int main(){                        //主体    int m;    while(~scanf("%d%d",&m,&n)){        init();        for(int i=0;i<m;i++){            int u,v,w;            scanf("%d%d%d",&u,&v,&w);            add_edge(u,v,w);        }        s=1,t=n;        int ans=sap(1,n,n);        printf("%d\n",ans);    }    return 0;}

Admiral
题意: 有n个点m条边,求从1到n的不相交,且费用最小的两条路,输出最小和费用
思路: 不相交 ——> 拆除了1,n的所有点,拆出的边限流1
两条路 ——> 拆1,n点,限流2
费用最小——> 最小费用最大流
剩下的套模板就好啦~

#include <iostream>#include <cstdio>#include <cstring>#include <queue>#include <string>#include <cmath>#include <algorithm>using namespace std;const int maxm=50010;const int maxn=2005;const int INF=1e9;#define type intint s, t;struct node {    int u, v, next;    type cap, flow, cost;}edge[maxm];int head[maxn], cnt;int pre[maxn];type dis[maxn];bool vis[maxn];int N;void init () {    memset (head, -1, sizeof head);    cnt = 0;}void add_edge (int u, int v, type cap, type cost) {    edge[cnt].u = u, edge[cnt].v = v, edge[cnt].cap = cap, edge[cnt].flow = 0;    edge[cnt].cost = cost, edge[cnt].next = head[u], head[u] = cnt++;    edge[cnt].u = v, edge[cnt].v = u, edge[cnt].cap = 0, edge[cnt].flow = 0;    edge[cnt].cost = -cost, edge[cnt].next = head[v], head[v] = cnt++;}bool spfa (int s, int t) {    queue <int> q;    for (int i = 0; i <= N; i++) {        dis[i] = INF;        vis[i] = 0;        pre[i] = -1;    }    dis[s] = 0;    vis[s] = 1;    q.push (s);    while (!q.empty ()) {        int u = q.front (); q.pop ();        vis[u] = 0;        for (int i = head[u]; i != -1; i = edge[i].next) {            int v = edge[i].v;            if (edge[i].cap > edge[i].flow && dis[v] > dis[u]+edge[i].cost) {                dis[v] = dis[u]+edge[i].cost;                pre[v] = i;                if (!vis[v]) {                    vis[v] = 1;                    q.push (v);                }            }        }    }    if (pre[t] == -1)        return 0;    else        return 1;}int MCMF (int s, int t, type &cost) {    type flow = 0;    cost = 0;    while (spfa (s, t)) {        type Min = INF;        for (int i = pre[t]; i != -1; i = pre[edge[i^1].v]) {            if (Min > edge[i].cap-edge[i].flow) {                Min = edge[i].cap-edge[i].flow;            }        }        for (int i = pre[t]; i != -1; i = pre[edge[i^1].v]) {            edge[i].flow += Min;            edge[i^1].flow -= Min;            cost += edge[i].cost*Min;        }        flow += Min;    }    return flow;}int main(){    int m;    while(~scanf("%d%d",&N,&m)){        init();        for(int i=0;i<m;i++){            int u,v,w;            scanf("%d%d%d",&u,&v,&w);            add_edge(u+N,v,1,w);   //想想为什么是u+N        }        s=1,t=2*N;        add_edge(1,1+N,2,0);   //拆1,n点        add_edge(N,2*N,2,0);        for(int i=2;i<=N-1;i++){            add_edge(i,i+N,1,0);  //拆其他点        }        int cost;        N=2*N;   //注意全局变量N的含义,细节        int flow=MCMF(1,N,cost);        printf("%d\n",cost);    }    return 0;}

Going Home
题意: 给一个N*M的矩阵,矩阵中m与h的个数相同,m与h之间的距离为横纵方向相差的格子数之和,输出给每个m匹配一个h后,最小的距离之和 (m可以穿过h所在的格子,N,M,h的个数都<=100)
思路: 显然的二分匹配,在每个m与h之间加边,费用为距离差
建立一超级源点,超级汇点,与每个m或h的边费用为1,套最小费用最大流的模板

#include <iostream>#include <cstdio>#include <string>#include <algorithm>#include <cmath>#include <cstring>#include <vector>#include <queue>using namespace std;const int INF=1<<29;const int maxn=610;const int maxm=30010;#define type intint s, t;struct node {    int u, v, next;    type cap, flow, cost;}edge[maxm];int head[maxn], cnt;int pre[maxn];type dis[maxn];bool vis[maxn];int N;void init () {    memset (head, -1, sizeof head);    cnt = 0;}void add_edge (int u, int v, type cap, type cost) {    edge[cnt].u = u, edge[cnt].v = v, edge[cnt].cap = cap, edge[cnt].flow = 0;    edge[cnt].cost = cost, edge[cnt].next = head[u], head[u] = cnt++;    edge[cnt].u = v, edge[cnt].v = u, edge[cnt].cap = 0, edge[cnt].flow = 0;    edge[cnt].cost = -cost, edge[cnt].next = head[v], head[v] = cnt++;}bool spfa (int s, int t) {    queue <int> q;    for (int i = 0; i < N; i++) {        dis[i] = INF;        vis[i] = 0;        pre[i] = -1;    }    dis[s] = 0;    vis[s] = 1;    q.push (s);    while (!q.empty ()) {        int u = q.front (); q.pop ();        vis[u] = 0;        for (int i = head[u]; i != -1; i = edge[i].next) {            int v = edge[i].v;            if (edge[i].cap > edge[i].flow && dis[v] > dis[u]+edge[i].cost) {                dis[v] = dis[u]+edge[i].cost;                pre[v] = i;                if (!vis[v]) {                    vis[v] = 1;                    q.push (v);                }            }        }    }    if (pre[t] == -1)        return 0;    else        return 1;}int MCMF (int s, int t, type &cost) {    type flow = 0;    cost = 0;    while (spfa (s, t)) {        type Min = INF;        for (int i = pre[t]; i != -1; i = pre[edge[i^1].v]) {            if (Min > edge[i].cap-edge[i].flow) {                Min = edge[i].cap-edge[i].flow;            }        }        for (int i = pre[t]; i != -1; i = pre[edge[i^1].v]) {            edge[i].flow += Min;            edge[i^1].flow -= Min;            cost += edge[i].cost*Min;        }        flow += Min;    }    return flow;}struct Node{    int x,y;};vector<Node> man,house;int main(){    int nn,m;    while(~scanf("%d%d",&nn,&m)&&nn){            init();        char c[110];        man.clear();  //用途理清        house.clear();        for(int i=0;i<nn;i++){            scanf("%s",c);            for(int j=0;j<m;j++)                if(c[j]=='H') house.push_back(Node{i,j});                else if(c[j]=='m') man.push_back(Node{i,j});        }        int tot=house.size();          s=0,t=2*tot+1;        N=2*tot+2;         //每次总点数这边都很容易理错……  多理几遍        for(int i=0;i<tot;i++){            add_edge(0,i+1,1,0);   //给每个man连超级源点            for(int j=0;j<tot;j++)                add_edge(i+1,j+1+tot,1,abs(man[i].x-house[j].x)+abs(man[i].y-house[j].y));  //每个man和house连边            add_edge(i+1+tot,2*tot+1,1,0);  //给每个house连超级汇点        }        int cost;        MCMF(0,2*tot+1,cost);  //套模板        printf("%d\n",cost);    }    return 0;}

啊这是我WA了>20次,debug两个小时,最后还是觉得一开始代码没问题的题 ~嗷
还是网络流题目做的不熟,代码写的不够优美,姿势不太标准吧……

Delivery Bears*********
题意: 有x只熊,从带费用网络流图的点1走到n,要求每只熊背的重量相同,求n点能接收到的最大总重量(每只熊背的重量*x)
思路: 一开始想到了二分,但卡在怎么检查mid的值上,后来还是学长给了思路。
将每条路的权值除以mid,就得出每只熊背mid重量的物品时,每条路能通过的最多的熊的数量,源点和汇点拆成权为x的边,然后最大流跑一遍,判断一下是否ans==x即可
代码还是要好好理一下啊

#include <iostream>#include <cstdio>#include <string>#include <cstring>#include <cmath>#include <iomanip>#include <algorithm>using namespace std;#define type intconst int INF=1<<29;const int maxn=600;const int maxm=20010;int n,m;int s, t;struct Edge {    int from, to, next;    type cap, flow;    void get (int u, int a, int b, type c, type d) {        from = u; to = a; next = b; cap = c; flow = d;    }}edge[maxm];int tol;int head[maxn];int gap[maxn], dep[maxn], pre[maxn], cur[maxn];void init () {    tol = 0;    memset (head, -1, sizeof head);}void add_edge (int u, int v, type w, type rw=0) {    edge[tol].get(u, v,head[u],w,0);head[u]=tol++;    edge[tol].get(v, u,head[v],rw,0);head[v]=tol++;}type sap (int start, int eend, int N) {    memset (gap, 0, sizeof gap);    memset (dep, 0, sizeof dep);    memcpy (cur, head, sizeof head);    int u = start;    pre[u] = -1;    gap[0] = N;    type ans = 0;    while (dep[start] < N) {        if (u == eend) {            type Min = INF;            for (int i = pre[u]; i != -1; i = pre[edge[i^1].to])                if (Min > edge[i].cap - edge[i].flow)                   Min = edge[i].cap-edge[i].flow;            for (int i = pre[u]; i != -1; i = pre[edge[i^1].to]) {                edge[i].flow += Min;                edge[i^1].flow -= Min;            }            u = start;            ans += Min;            continue;        }        bool flag = false;        int v;        for (int i = cur[u]; i != -1; i = edge[i].next) {            v = edge[i].to;            if (edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]) {                flag = true;                cur[u] = pre[v] = i;                break;            }        }        if (flag) {            u = v;            continue;        }        int Min = N;        for (int i = head[u]; i != -1; i = edge[i].next)            if (edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) {                      Min = dep[edge[i].to];                      cur[u] = i;                 }        gap[dep[u]]--;        if (!gap[dep[u]]) return ans;        dep[u] = Min+1;        gap[dep[u]]++;        if (u != start) u = edge[pre[u]^1].to;    }    return ans;}struct rese{    int u,v;    int w;}res[maxm];int x;bool check( double mid){    init();    for(int i=0;i<m;i++)        add_edge(res[i].u,res[i].v,min((res[i].w/mid),1.0*x));  //注意min函数里面比较的类型应该一致    add_edge(0,1,x);    add_edge(n-2,n-1,x);    int ans=sap(0,n-1,n);    if(ans==x) return true;    else return false;}int main(){     //论如何将代码写的更加优美==    scanf("%d%d%d",&n,&m,&x);        init();        for(int i=0;i<m;i++){            scanf("%d%d%d",&res[i].u,&res[i].v,&res[i].w);        }        n+=2;  //最后错原来在这里……   n是包括超级源点和汇点的总点数,之前忘了+2,check函数中也没有注意噗。。        double l=0;        double r=1e9;        double mid,ans=0;        for(int i=0;i<100;i++){  //用这样的循环会比eps更加精确            mid=(r+l)/2;            if(check(mid))                l=mid,ans=mid;            else                r=mid;        }        printf("%.10f\n",ans*x);    return 0;}

最后两题是紫书上的原题,重点复习最后一题
A Plug of Unix
题意: 有n个设备,m个插座,k个转换器,转换器可以叠加使用且数量无限(开始没审清题意噗。。),求最少有多少个设备无法充电
思路: 建立一个超级源点与汇点,将所有的插头插座种类都加进图中
若是设备的插头,则与超级源点连一条上限为1的边
若是插座,则与超级汇点连一条上限为1的边
是转换器x->y,则在x与y之间连一条上限无穷大的有向边

#include <iostream>#include <cstring>#include <cstdio>#include <string>#include <cstdlib>#include <cmath>#include <map>#include <vector>#include <algorithm>using namespace std;const int INF=1e9;const int maxn=1010;const int maxm=10000;#define type intint n;int s, t;struct Edge {    int from, to, next;    type cap, flow;    void get (int u, int a, int b, type c, type d) {        from = u; to = a; next = b; cap = c; flow = d;    }}edge[maxm];int tol;int head[maxn];int gap[maxn], dep[maxn], pre[maxn], cur[maxn];void init () {    tol = 0;    memset (head, -1, sizeof head);}void add_edge (int u, int v, type w, type rw=0) {    //cout << u << " " << v << " " << w << endl;    edge[tol].get(u, v,head[u],w,0);head[u]=tol++;    edge[tol].get(v, u,head[v],rw,0);head[v]=tol++;}type sap (int start, int eend, int N) {    memset (gap, 0, sizeof gap);    memset (dep, 0, sizeof dep);    memcpy (cur, head, sizeof head);    int u = start;    pre[u] = -1;    gap[0] = N;    type ans = 0;    while (dep[start] < N) {        if (u == eend) {            type Min = INF;            for (int i = pre[u]; i != -1; i = pre[edge[i^1].to])                if (Min > edge[i].cap - edge[i].flow)                   Min = edge[i].cap-edge[i].flow;            for (int i = pre[u]; i != -1; i = pre[edge[i^1].to]) {                edge[i].flow += Min;                edge[i^1].flow -= Min;            }            u = start;            ans += Min;            continue;        }        bool flag = false;        int v;        for (int i = cur[u]; i != -1; i = edge[i].next) {            v = edge[i].to;            if (edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]) {                flag = true;                cur[u] = pre[v] = i;                break;            }        }        if (flag) {            u = v;            continue;        }        int Min = N;        for (int i = head[u]; i != -1; i = edge[i].next)            if (edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) {                      Min = dep[edge[i].to];                      cur[u] = i;                 }        gap[dep[u]]--;        if (!gap[dep[u]]) return ans;        dep[u] = Min+1;        gap[dep[u]]++;        if (u != start) u = edge[pre[u]^1].to;    }    return ans;}map<string,int> mark;  //给不同种的插头插座编号int ID(string name){    if(mark.count(name)) return mark[name];    else{        mark[name]=n++;  //n在这里计数,理解含义        return mark[name];    }}int main(){    int tt;    scanf("%d",&tt);    while(tt--){        init();        mark.clear();        n=1;        int N,M;        scanf("%d",&M);        s=0,t=1000;        vector<int> vec;        for(int i=0;i<M;i++){ //设备            string name;            cin>>name;            int id=ID(name);            vec.push_back(id);        }        scanf("%d",&N);        for(int i=0;i<N;i++){ //插座            string name,plug;            cin>>name>>plug;            int id=ID(plug);            add_edge(0,id,1);        }        int m;        scanf("%d",&m);        for(int i=0;i<m;i++){ //转换器            string a,b;            cin>>a>>b;            int aa=ID(a);            int bb=ID(b);            add_edge(aa,bb,INF);        }        for(int i=0;i<vec.size();i++) //注意这个放置的顺序==,得放在转换器读完之后==            add_edge(vec[i],n,1);        int ans=sap(0,n,n+1);        printf("%d\n",N-ans);        if(tt) printf("\n");    }    return 0;}

哈哈哈哈终于到了最后一题
Matrix decompressing***************
题意: 一个R*C数阵, 已知前i行之和R[i](1<=i<=R)和前j列之和C[j](1<=j<=C),输出一个满足条件的矩阵 (1<=R,C,矩阵中每个数<=20)
思路:
这个思路很神奇,将题目化作二分匹配来做
可以求解出每行每列的数字之和,R’[i],C’[j]
让矩阵中每个数都减一,则每一行的值减C(R’[i]-C),每一列的值减R (C’[j]-R)
建立超级源点和汇点,超级源点与代表行的点相连,上限为R’[i]-C,超级汇点与代表列的点相连,上限为C’[j]-R
代表行的点与每个代表列的点相连,上限为19

求一遍最大流,满流则有解,解为边最后的流量

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <algorithm>using namespace std;// 好巧妙的一题 *********#define type intconst int INF=1e9;const int maxn=200;const int maxm=1050;int n;int s, t;struct Edge {    int from, to, next;    type cap, flow;    void get (int u, int a, int b, type c, type d) {        from = u; to = a; next = b; cap = c; flow = d;    }}edge[maxm];int tol;int head[maxn];int gap[maxn], dep[maxn], pre[maxn], cur[maxn];void init () {    tol = 0;    memset (head, -1, sizeof head);}void add_edge (int u, int v, type w, type rw=0) {    //cout << u << " " << v << " " << w << endl;    edge[tol].get(u, v,head[u],w,0);head[u]=tol++;    edge[tol].get(v, u,head[v],rw,0);head[v]=tol++;}type sap (int start, int eend, int N) {    memset (gap, 0, sizeof gap);    memset (dep, 0, sizeof dep);    memcpy (cur, head, sizeof head);    int u = start;    pre[u] = -1;    gap[0] = N;    type ans = 0;    while (dep[start] < N) {        if (u == eend) {            type Min = INF;            for (int i = pre[u]; i != -1; i = pre[edge[i^1].to])                if (Min > edge[i].cap - edge[i].flow)                   Min = edge[i].cap-edge[i].flow;            for (int i = pre[u]; i != -1; i = pre[edge[i^1].to]) {                edge[i].flow += Min;                edge[i^1].flow -= Min;            }            u = start;            ans += Min;            continue;        }        bool flag = false;        int v;        for (int i = cur[u]; i != -1; i = edge[i].next) {            v = edge[i].to;            if (edge[i].cap - edge[i].flow && dep[v]+1 == dep[u]) {                flag = true;                cur[u] = pre[v] = i;                break;            }        }        if (flag) {            u = v;            continue;        }        int Min = N;        for (int i = head[u]; i != -1; i = edge[i].next)            if (edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) {                      Min = dep[edge[i].to];                      cur[u] = i;                 }        gap[dep[u]]--;        if (!gap[dep[u]]) return ans;        dep[u] = Min+1;        gap[dep[u]]++;        if (u != start) u = edge[pre[u]^1].to;    }    return ans;}int row[25],cow[25];int main(){                        //重点    int tt;scanf("%d",&tt);    int cas=1;    while(tt--){        init();        int r,c;        scanf("%d%d",&r,&c);  //读入        for(int i=0;i<r;i++)            scanf("%d",&row[i]);        for(int i=0;i<c;i++)            scanf("%d",&cow[i]);          //处理出每一行每一列的和        for(int i=r-1;i>0;i--) row[i]-=row[i-1];        for(int j=c-1;j>0;j--) cow[j]-=cow[j-1];        s=0,t=r+c+1;        n=r+c+2;        //超级源点,超级汇点加边        for(int i=0;i<r;i++)            add_edge(0,i+1,row[i]-c);        for(int j=0;j<c;j++)            add_edge(r+j+1,r+c+1,cow[j]-r);         //行的点与列的点之间加边,注意加边顺序        for(int i=0;i<r;i++)        for(int j=c-1;j>=0;j--)  //这里放入边的顺序会影响最后的输出顺序            add_edge(i+1,r+j+1,19);        sap(0,r+c+1,r+c+2);        printf("Matrix %d\n",cas++);        for(int i=1;i<=r;i++){            for(int j=head[i];edge[j].next!=-1;j=edge[j].next){  //head[u]存以u为起点的所以边的值,注意最后一条是到超级源点的逆序边                printf("%d",edge[j].flow+1);                if(edge[edge[j].next].next!=-1) printf(" ");            }            printf("\n");        }    }    return 0;}

图论这才刚刚开始,加油吧少年~

原创粉丝点击