网络流24题-18

来源:互联网 发布:笑郭网络验证4.6 编辑:程序博客网 时间:2024/06/13 21:40

分配问题

«问题描述:
有 n 件工作要分配给 n 个人做。第 i 个人做第 j 件工作产生的效益为 c ij 。试设计一个将
n 件工作分配给 n 个人做的分配方案,使产生的总效益最大。
«编程任务:
对于给定的 n 件工作和 n 个人,计算最优分配方案和最差分配方案。
«数据输入:
由文件 input.txt 提供输入数据。文件的第 1 行有 1 个正整数 n,表示有 n 件工作要分配
给 n 个人做。接下来的 n 行中,每行有 n 个整数 c ij ,1≤i≤n,1≤j≤n,表示第 i 个人做
第 j 件工作产生的效益为 c ij 。
«结果输出:
程序运行结束时,将计算出的最小总效益和最大总效益输出到文件 output.txt 中。
输入文件示例
input.txt
5
2 2 2 1 2
2 3 1 2 4
2 0 1 1 1
2 3 4 3 3
3 2 1 2 1
输出文件示例
output.txt
5
14

【问题分析】

费用流问题。

【建模方法】

把所有仓库看做二分图中顶点Xi,所有零售商店看做二分图中顶点Yi,建立附加源S汇T。

1、从S向每个Xi连一条容量为仓库中货物数量ai,费用为0的有向边。
2、从每个Yi向T连一条容量为商店所需货物数量bi,费用为0的有向边。
3、从每个Xi向每个Yj连接一条容量为无穷大,费用为cij的有向边。

求最小费用最大流,最小费用流值就是最少运费,求最大费用最大流,最大费用流值就是最多运费。

【建模分析】

把每个仓库想象成一个中转站,由源点运来ai单位货物,运费为0,每个商店也为一个中转站,运向目标汇点bi单位货物。每个仓库和零售商店之间有一条道路,容量为无穷大,费用为单位运费cij。求从源点到汇点的费用流,就是运费。

#include<iostream>#include<math.h>#include<cstring>#include<algorithm>#include<set>#include<map>#include<queue>#include<cstdio>#include<vector>const int INF=0x7fffffff;const int maxn=1000;int Map[maxn+1][maxn+1];using namespace std;struct edge{    int to,cap,cost,rev;};vector<edge> G[maxn];int dist[maxn],prevv[maxn],preve[maxn];int V,S,T,N;void add_edge(int from,int to,int cap,int cost){    G[from].push_back((edge){to,cap,cost,G[to].size()});    G[to].push_back((edge){from,0,-cost,G[from].size()-1});    //cout<<from<<"to:"<<to<<" "<<cap<<" "<<cost<<endl;}int min_cost_flow(int s,int t,int f){    int res=0;    while(f>0)    {        fill(dist,dist+V+1,INF);        bool update=true;        dist[s]=0;        while(update)        {            update=false;            for(int v=0;v<=V;v++)            {                if(dist[v]==INF)                    continue;                for(int i=0;i<G[v].size();i++)                {                    edge &e=G[v][i];                    if(e.cap&&dist[e.to]>dist[v]+e.cost)                    {                        dist[e.to]=dist[v]+e.cost;                        prevv[e.to]=v;                        preve[e.to]=i;                        update=true;                    }                }            }        }        if(dist[t]==INF)            return -1;        int d=f;        for(int v=t;v!=s;v=prevv[v])            d=min(G[prevv[v]][preve[v]].cap,d);        f-=d;        res+=d*dist[t];        for(int v=t;v!=s;v=prevv[v])        {            edge &e=G[prevv[v]][preve[v]];            e.cap-=d;            G[e.to][e.rev].cap+=d;        }    }    return res;}void init(){    cin>>N;    S=0;    T=2*N+1;    V=T;    for(int i=1;i<=N;i++)        for(int j=1;j<=N;j++)            cin>>Map[i][j];}void solve1(){    for(int i=1;i<=N;i++)        add_edge(S,i,1,0);    for(int i=1;i<=N;i++)        add_edge(i+N,T,1,0);    for(int i=1;i<=N;i++)        for(int j=1;j<=N;j++)            add_edge(i,j+N,1,Map[i][j]);    int ans=min_cost_flow(S,T,N);    cout<<ans<<endl;}void solve2(){    for(int i=1;i<=N;i++)        add_edge(S,i,1,0);    for(int i=1;i<=N;i++)        add_edge(i+N,T,1,0);    for(int i=1;i<=N;i++)        for(int j=1;j<=N;j++)            add_edge(i,j+N,1,-Map[i][j]);    int ans=min_cost_flow(S,T,N);    cout<<-ans<<endl;}int main(){    init();    solve1();    for(int i=0;i<=V;i++)        G[i].clear();    solve2();    return 0;}
原创粉丝点击