POJ 2516 Minimum Cost

最小费用流第一题,这个卡的……

最后认真膜拜了大神的博客   终于做出来了!!!


题目大意:

有N个店铺,M个供货商,K种商品。给出每个供货商的仓库里每种商品的数量、每种商品给每个店铺供货的费用,每个店铺需要的各种商品的数量,求最小费用。 


输入一开始是N,M,K。

然后 N行   ,每行 K列 ,第I行第J个数代表 第I个店铺 需要第J种物品多少件。

然后 M行  ,每行 K列 , 第I行第J个数代表 第I个供货商 有第J种物品多少件。

然后是K个矩阵  ,每个N行M列,第I个矩阵的第J行第D列代表着第D个供货商给第J个店铺发第I种货物一件需要的花费。


(输入的地方比较坑爹,请大家注意)


下面是代码:

#include <stdio.h>
#include <string.h>
#include <queue>

using namespace std;

const int M=105,inf=1<<30;
int need[M][M],have[M][M],cost[M][M][M],n,m,k;
int c[M][M];//针对某种物品的最大容量
int f[M][M];//流量
int w[M][M];//费用
int dis[M];//最短路算法中的距离数组,记录原点到其他点的距离
int pre[M];  //最短路中的记录数组,记录最短路径
bool vis[M]; //最短路算法中的标记数组  标记是否被访问过
int min(int a,int b)
{
    if(a>b)
    {
        a=b;
    }
    return a;
}
bool spfa() //最少的费用,最短路算法
{
    int i,j;
    for(i=0;i<=n+m+1;i++)  //初始化
    {
        dis[i]=inf;
        pre[i]=-1;
        vis[i]=false;
    }
    dis[0]=0;
    vis[0]=true;
    queue <int > q;
    q.push(0);  //初始化完成
    while(!q.empty())
    {
        int t=q.front();
        q.pop();
        vis[t]=false;
        for(i=1;i<=n+m+1;i++)
        {
            if(c[t][i]>f[t][i]&&dis[i]>dis[t]+w[t][i])  //如果流量没有到最大且超级原点经过点t到i的费用比直接到i小
            {
                dis[i]=dis[t]+w[t][i]; //更新到i点的最小花费
                pre[i]=t; //更新最短路径中点i的前驱为t
                if(!vis[i]) //如果点i没在队列中
                {
                    q.push(i);   //将点i放入队列
                    vis[i]=true; //标记已在队列中
                }
            }
        }
    }
    if(pre[n+m+1]==-1)//如果超级汇点没有在对短路中 (因为没有前驱)
    {
        return false;//返回寻找最短路失败
    }
    return true;  //返回最短路寻找成功
}
void getMaxflow()  //寻找增广路
{
    while(spfa())//如果最最小费用增广路寻找成功
    {
        int maxflow=inf;//初始化为最大值
        int p=n+m+1;
        while(pre[p]!=-1) //遍历最小费用增广路
        {
            maxflow=min(maxflow,c[pre[p]][p]-f[pre[p]][p]);//寻找关键流量,及最短路上的最小流量
            p=pre[p];
        }
        p=n+m+1; //再次初始化;
        while(pre[p]!=-1)  //再次遍历最小费用增广路
        {
            f[pre[p]][p]+=maxflow;
            f[p][pre[p]]=-f[pre[p]][p];  //调整流量
            p=pre[p];
        }
    }
}
int main()
{
    int i,j,d,ans;
    while(scanf("%d%d%d",&n,&m,&k),n||m||k)
    {
        ans=0;
        bool flat=false;
        for(i=1;i<=n;i++) //输入部分  
        {
            for(j=1;j<=k;j++)
            {
                scanf("%d",&need[i][j]);
            }
        }
        for(i=1;i<=m;i++)
        {
            for(j=1;j<=k;j++)
            {
                scanf("%d",&have[i][j]);
            }
        }
        for(i=1;i<=k;i++)
        {
            for(j=1;j<=n;j++)
            {
                for(d=1;d<=m;d++)
                {
                    scanf("%d",&cost[i][d][j]);
                }
            }
        } //输入部分完成
        for(i=1;i<=k;i++)//对于每一种货物来说
        {
            memset(c,0,sizeof(c));
            memset(f,0,sizeof(f));
            memset(w,0,sizeof(w));
            for(j=1;j<=m;j++)
            {
                c[0][j]=have[j][i];//超级远点到每个仓库的流量应该是仓库的存货量
            }
            for(j=1;j<=n;j++)
            {
                c[m+j][m+n+1]=need[j][i];//每个商店到超级汇点的容量应该是这个商店的需求量
            }
            for(j=1;j<=m;j++)
            {
                for(d=1;d<=n;d++)
                {
                    c[j][d+m]=have[j][i];//每个仓库到商店的容量应该是仓库的存货量
                }
            }
            for(j=1;j<=m;j++)
            {
                for(d=1;d<=n;d++)
                {
                    w[j][d+m]=cost[i][j][d];  //供货商到商店的花费
                    w[d+m][j]=-cost[i][j][d]; //花费的负值,用于回流时
                }
            }
            getMaxflow();//对第i种商品寻找最小费用流
            for(j=1;j<=n;j++) //对于每一个商店来说
            {
                if(c[j+m][n+m+1]!=f[j+m][n+m+1]) //如果供货量不等于需求量
                {
                    flat=true;
                    break;
                }
            }
            if(flat)  //出现供货不足    跳出
            {
                break;
            }
            for(j=1;j<=m;j++)
            {
                for(d=1;d<=n;d++)
                {
                    ans+=f[j][d+m]*w[j][d+m];//计算总费用
                }
            }
        }
        if(flat)//出现供货不足
        {
            printf("-1\n");
        }
        else
        {
            printf("%d\n",ans);
        }
    }
    return 0;
}


你可能感兴趣的:(poj,SPFA,流量,刷题)