zkw最小费用流模板,输出流量路径

#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#define eps 1e-5

using namespace std;
const int maxn = 1000;
const int maxm = 50000;
const int INF = 0x3f3f3f3f;

typedef long long ll;


struct MaxFlow
{
    int size, n;
    int s, t, k,  maxflow, mincost;
    bool vis[maxn];
    int net[maxn], pre[maxn], cur[maxn], dis[maxn];
    std::queue <int> Q;
    
    int netNode,consumeNode, serverCost;
    //输出
    vector<int> res[maxn];  // p条输出路径
    vector<int> outFlow;  //p条路径的 各自流量
    int outCnt; //记录有多少条输出路径
    
    //for search path
    int fa[1505];
    int find_flow;
    int p_edge[1505]; //点对应的边的编号
    int ok;
    int find_vis[1505];
    
    
    struct EDGE
    {
        int v, cap, cost, next ,flow;
        EDGE() {}
        EDGE(int a, int b, int c, int d ,int e)
        {
            v = a, cap = b, cost = c, next = d;
            flow = e;
        }
    } E[maxm << 1];
    
    
    
    void init(int _n)
    {
        n = _n, size = 0;
        memset(net, -1, sizeof(net));
    }
    
    void add(int u, int v, int cap, int cost)
    {
        E[size] = EDGE(v, cap, cost, net[u] , 0);
        net[u] = size++;
        E[size] = EDGE(u, 0, -cost, net[v] , 0);
        net[v] = size++;
    }
    
    bool adjust()
    {
        int v, min = INF;
        for (int i = 0; i < n; i++)
        {
            if (!vis[i])
                continue;
            for (int j = net[i];  j != -1; j = E[j].next){
                v = E[j].v;
                if (E[j].cap > E[j].flow)
                    if (!vis[v] && dis[v] - dis[i] + E[j].cost < min)
                        min = dis[v] - dis[i] + E[j].cost;
            }
        }
        if (min == INF)
            return false;
        for (int i = 0; i <n; i++)
            if (vis[i])
                cur[i] = net[i], vis[i] = false, dis[i] += min;
        return true;
    }
    
    //找增广路
    int augment(int i, int flow)
    {
        if (i == t)
        {
            mincost += dis[s] * flow;
            maxflow += flow;
            return flow;
        }
        vis[i] = true;
        
        for (int j = cur[i], v; v = E[j].v, j != -1; j = E[j].next)
            if (E[j].cap > E[j].flow){
                
                if (vis[v] || dis[v] + E[j].cost != dis[i]) continue;
        
                int delta = augment(v, std::min(flow, E[j].cap - E[j].flow));
                if (delta)
                {
                    E[j].flow += delta;
                    E[j ^ 1].flow -= delta;
                    cur[i] = j;
                    return delta;
                }
            }
        
        return 0;
    }
    
    
    int zkw(int _s, int _t, int need)
    {
        s = _s, t = _t;
        
        mincost = maxflow = 0;
        for (int i = 0; i < n; i++){
            vis[i] = false;
            cur[i] = net[i];
        }
        
        do
        {
            while (augment(s, INF))
                memset(vis, false, sizeof(vis));
        } while (adjust());
        if (maxflow < need)
            return -1;
        return mincost;
    }
    
    
    //------------- for search path
    
    void update_flow(int minflow , int fa[]){
        //从s开始
        int cnt = outCnt;
        // printf("cnt=%d: minflow=%d\n",cnt, minflow);
        int u=t;
        while(u!=s){
            
            //流量更新,减掉minflow
            //  if(p[u]==s) printf("p_edeg=%d ,s.flow=%d ",p_edge[u], edges[p_edge[u]].flow);
            //edges[p_edge[u]].flow -=minflow;
            E[p_edge[u]].flow -=minflow;
            if(u != s) res[cnt].push_back(u);
            //   if(p[u]==s) printf("^^^^ , s.flow=%d \n",edges[p_edge[u]].flow);
            u = fa[u];
        }
        outFlow.push_back(minflow);
        
        
        find_flow += minflow;
        outCnt++;
    }
    
    
    //cur表示当前点
    void dfs_findPath(int cur, int minflow){
        
        if(ok) return;
        
        //从s正方向找
        if(cur == t){
            
            //更新整条路上的 流量
            update_flow(minflow, fa);
            ok=1;
            return ;
        }
        
        for (int i = net[cur] , v; v = E[i].v, i != -1; i = E[i].next){
            
            if(E[i].flow<=0) continue; //反向边不搜索
            if(find_vis[v]) continue;
            
            fa[v] = cur;
            p_edge[v] = i;
            find_vis[v] = 1;
            
            dfs_findPath(v , min(minflow, E[i].flow));
            
            find_vis[v] = 0;
            
            if(ok) return;
            
        }
        
    }
    
    
    
    
    void search_path(){
        
        printf("search start\n");
        outCnt = 0;
        for(int i=0; i<1500;i++)
        {
            res[i].clear();
            outFlow.clear();
        }
        find_flow = 0;
        fa[s] = -1;
        while(find_flow< k ){
            
            // for(int i=0; i<(int)G[st].size(); i++){
            for (int i = net[s] , v; v = E[i].v, i != -1; i = E[i].next){
                //puts("ss");
                // printf("i=%d, e.flow =%d e.from =%d, e.to =%d\n",i, e.flow , e.flow , e.to);
                fa[v] = s;
                p_edge[v] = i;
                
                if(E[i].flow>0) {  //搜路径 ,初始为服务点
                    ok=0;
                    memset(find_vis, 0, sizeof(find_vis));
                    find_vis[s] = 1;
                    dfs_findPath(v , INF);
                }
                
                
            }
        }
    }
    
    //输出流量路径
    void OutputPath(string& str){
        char c[50];
        
         printf("outCnt = %d\n\n", outCnt);
        sprintf(c, "%d\n\n", outCnt);
        str += c;
        
        for(int i=0; i< outCnt ;i++){
            for(int j= (int)res[i].size()-1 ; j>0; j--)
            {
                       printf("%d ",res[i][j]>=netNode?(res[i][j]-netNode):res[i][j]);
                sprintf(c,"%d ",res[i][j]>=netNode?(res[i][j]-netNode):res[i][j]);
                str +=c;
            }
             printf("%d\n",outFlow[i]);
            sprintf(c, "%d\n",outFlow[i]);
            str +=c;
        }
    }
} zkw;




int main(){
    
    struct MaxFlow ob;
    int cnt;
    int netNode,consumeNode, serverCost;
    int s,t;
    int from, to , cap , cost;
    string str;
    
    freopen("case1.txt", "r+" , stdin);
    // freopen("out.txt", "w+", stdout);
    
    //网络节点数量 网络链路数量 消费节点数量
    scanf("%d%d%d",&netNode, &cnt , &consumeNode);
    scanf("%d", &serverCost);
    ob.netNode = netNode;
    ob.consumeNode = consumeNode;
    ob.serverCost = serverCost;
    
    s = netNode+consumeNode;
    t = s+1;
    ob.init(netNode+consumeNode+2);
    
    //网络点
    while(cnt--){
        
        scanf("%d%d%d%d",&from , &to, &cap, &cost);
        ob.add(from, to, cap, cost);
        ob.add(to, from, cap, cost);
    }
    
    int indx,nodeID;
    ob.k = 0;
    //消费点
    for(int i=0; i<consumeNode; i++){
        scanf("%d%d%d",&indx, &nodeID, &cap);
        ob.k += cap;
        //与网络点
        ob.add(indx + netNode, nodeID, cap, 0);
        ob.add(nodeID ,indx + netNode, cap, 0);
        
        //与t点
        ob.add(indx+netNode, t, cap, 0);
    }
    
    
    //int servers[]={0,3,22};
    int servers[]={6,7,13,17,35,41,48};
    //int servers[] = {12,18,23,29,31,38,48};
    int serverNum = 7;
    for(int i=0; i<serverNum ; i++){
        ob.add(s, servers[i], INF, 0);
    }
    
    int ans = ob.zkw(s, t, ob.k);
    printf("ans = %d\n",ans + serverCost*serverNum);
    ob.search_path();
    ob.OutputPath(str);
    
    return 0;
}


输入:case 1

50 97 9

280

0 25 21 9
0 22 27 1
0 18 33 10
0 14 15 1
0 13 45 8
0 9 29 1
0 6 13 10
0 1 6 3
0 2 21 1
0 3 46 10
0 4 14 8
1 35 40 5
1 26 36 7
1 2 28 2
1 3 29 1
1 4 32 7
2 25 40 8
2 24 35 3
2 14 19 10
2 39 33 1
2 36 17 3
2 33 2 7
2 29 7 2
2 3 17 5
2 4 2 2
3 13 38 7
3 15 4 7
3 41 15 10
3 4 35 2
4 22 6 8
4 24 42 7
4 6 22 10
4 39 33 2
4 49 2 1
4 46 5 4
5 6 39 5
7 8 46 1
7 9 23 3
7 10 7 4
8 9 4 2
8 10 22 10
9 45 17 5
9 10 33 2
11 12 37 10
11 13 29 4
12 13 33 3
14 15 25 3
16 30 46 6
16 17 37 1
16 18 48 9
16 19 2 10
16 20 4 2
17 18 25 7
17 19 21 8
17 20 16 7
18 19 29 8
18 20 1 6
19 24 13 4
19 20 32 8
20 33 5 1
21 22 9 8
21 23 35 6
22 23 32 1
24 36 21 9
24 25 19 3
26 27 25 2
26 28 14 8
27 28 48 1
28 36 25 4
29 30 18 2
30 44 17 6
31 32 38 2
31 33 20 10
32 33 19 1
34 35 2 6
34 36 38 6
34 37 49 2
35 36 6 9
35 37 40 3
36 37 32 10
38 39 44 4
38 40 23 6
39 40 37 10
40 44 21 2
41 42 23 1
41 43 25 1
42 43 48 1
44 45 19 3
44 46 4 1
44 47 35 9
44 48 46 10
45 46 49 5
45 47 38 1
45 48 29 5
46 47 22 8
46 48 16 7
47 48 50 7

0 35 57
1 5 10
2 6 32
3 7 28
4 41 25
5 13 99
6 48 82
7 17 27
8 23 21

demo

28 45 12

100

0 16 8 2
0 26 13 2
0 9 14 2
0 8 36 2
0 7 25 2
0 6 13 2
0 1 20 1
0 2 16 1
0 3 13 1
1 19 26 2
1 18 31 2
1 16 24 2
1 15 16 2
1 2 4 1
1 3 11 1
2 4 37 2
2 25 24 2
2 21 5 2
2 20 2 2
2 3 7 1
3 19 24 2
3 24 17 2
3 27 26 2
4 5 26 1
4 6 12 1
5 6 14 1
8 21 36 5
9 10 6 1
9 11 14 1
10 26 11 5
10 11 9 1
12 13 15 1
12 14 9 1
12 15 12 1
13 14 11 1
13 15 27 1
14 15 19 1
17 18 22 1
21 22 22 1
21 23 18 1
21 24 14 1
22 23 23 1
22 24 11 1
23 24 23 1
26 27 19 1

0 8 40
1 11 13
2 22 28
3 3 45
4 17 11
5 19 26
6 16 15
7 13 13
8 5 18
9 25 15
10 7 10
11 24 23
输入输出格式:

网络节点数量 网络链路数量 消费节点数量

视频内容服务器部署成本

链路起始节点ID 链路终止节点ID 总带宽大小 单位网络租用费
…………….(如上链路信息若干行)

消费节点ID 相连网络节点ID 视频带宽消耗需求

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值