文章标题 POJ 2516 : Minimum Cost (求k次 费用流)

题目链接
思路参考自 http://blog.csdn.net/lyy289065406/article/details/6742534

题意:有N个店主,M个供应商,还有K种物品,然后对于N个店主,每一个店主对K种物品每种都有一个需求,对于M个供应商,每个供应商对K种物品每种都有一个供应,然后知道第k种物品从第j个供应商运到第i个店主的单位费用。
分析:首先先判断对第k种物品是否能够供等于求或供过于求,否则就是无解的情况,直接输出-1。
当符合供过于求或者供等于求时,我们可以知道,对于k种物品是相互独立的,所以我们可以对这k个物品做k次费用流,然后将这k个物品的费用加起来就是答案,关键就是怎么建图,用0表示超级源点,用N+M+1表示超级汇点,然后1~M表示M个供应商,M+1~M+N表示N个店主,
然后
源点到供应商的边,流量为第k种物品的供应量,费用为0
店主到汇点的边,流量为第k种物品的需求量,费用为0
第j个供应商到第i个店主的边,流量为第k种物品的供应量,费用为j个供应商到第i个店主对第k种物品的单位费用
建完就跑费用流就行了,注意每次跑都都得初始化。
代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
typedef long long ll;

const int mod=1e9+7;
const int maxn=1000+10;
const int maxm=10005;

const int inf=0x3f3f3f3f;

struct Edge{
    int to,nex,cap,flow,cost;
};
//费用流。。 
struct MFMC{
    Edge edge[maxm];
    int head[maxn],tot;
    int pre[maxn],dis[maxn];
    bool vis[maxn];
    int N;//节点的总个数,节点编号从0~N-1;
    void init(int n){
        N=n;
        tot=0;
        memset (head,-1,sizeof (head));
    }

    void addedge(int u,int v,int cap,int cost){
        edge[tot]=Edge{v,head[u],cap,0,cost};
        head[u]=tot++;
        edge[tot]=Edge{u,head[v],0,0,-cost};
        head[v]=tot++;
    }

    bool spfa(int s,int t){
        queue<int>q;
        for (int i=0;ifalse;
            pre[i]=-1;
        }
        dis[s]=0;
        vis[s]=true;
        q.push(s);
        while (!q.empty()){
            int u=q.front();q.pop();
            vis[u]=false;
            for (int i=head[u];i!=-1;i=edge[i].nex){
                int v=edge[i].to;
                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]=true;
                        q.push(v);
                    }
                }
            }
        }
        if (pre[t]==-1)return false;
        else return true;
    }

    int minCostMaxflow(int s,int t,int &cost){
        int flow=0;
        cost=0;
        while (spfa(s,t)){
            int Min=inf;
            for (int i=pre[t];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[t];i!=-1;i=pre[edge[i^1].to]){
                edge[i].flow+=Min;
                edge[i^1].flow-=Min;
                cost+=edge[i].cost*Min;
            }
            flow+=Min;
        }
        return flow;
    }
}mfmc;

int N,M,K; 
int shopk[maxn][maxn];//shopk[i][j]表示第i个店主对第j种物品的需求 
int suppy[maxn][maxn];//suppy[i][j]表示第i个供应商对第j种物品的供应
int sum1[maxn],sum2[maxn];//sum1[i]表示第i中物品的总需求,sum2[i]表示第i种物品的总供应
int cost[maxn][maxn];//cost[i][j]表示第k种物品,从第j个供应商运送单位k物品到i店主的花费 
int main()
{
    while (scanf ("%d%d%d",&N,&M,&K)!=EOF){
        if (N==0&&M==0&&K==0)break;
        memset (sum1,0,sizeof (sum1));
        memset (sum2,0,sizeof (sum2)); 
        for (int i=1;i<=N;i++){
            for (int j=1;j<=K;j++){
                scanf ("%d",&shopk[i][j]);
                sum1[j]+=shopk[i][j];
            }
        } 
        for (int i=1;i<=M;i++){
            for (int j=1;j<=K;j++){
                scanf ("%d",&suppy[i][j]); 
                sum2[j]+=suppy[i][j];
            }
        }
        int flag=1;
        for (int i=1;i<=K;i++){
            if (sum1[i]>sum2[i]){//供不应求的情况 
                flag=0;break;
            } 
        }
        if (flag==0){//供不应求的情况,直接输出 -1 
            int tmp;
            for (int i=1;i<=K;i++){//数据还是得输入 
                for (int j=1;j<=N;j++){
                    for (int k=1;k<=M;k++){
                        scanf ("%d",&tmp);
                    }
                }
            }
            printf ("-1\n");
        }else {
            int ans=0;
            for(int k=1;k<=K;k++){
                for (int i=1;i<=N;i++) {
                    for (int j=1;j<=M;j++){
                        scanf ("%d",&cost[i][j]);//费用 
                    }
                } 
                mfmc.init(maxn);
                int st=0,la=N+M+1;
                for (int i=1;i<=M;i++){
                    mfmc.addedge(st,i,suppy[i][k],0);//源点到供应商 
                }
                for (int i=1;i<=N;i++){
                    mfmc.addedge(i+M,la,shopk[i][k],0);//店主到汇点 
                }
                for (int i=1;i<=N;i++){
                    for (int j=1;j<=M;j++){
                        mfmc.addedge(j,i+M,suppy[j][k],cost[i][j]);//供应商到店主 
                    }
                }
                int c=0;
                mfmc.minCostMaxflow(st,la,c);//c在函数中还会被初始化为0,所以不能传进ans 
                ans+=c;
            }
            printf ("%d\n",ans); 
        }
    }
    return 0;
}

你可能感兴趣的:(图,网络流)