题目链接
思路参考自 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;
}