题目:
给出n*kk的矩阵,格子a[i][k]表示第i个客户需要第k种货物a[i][k]单位。
给出m*kk的矩阵,格子b[j][k]表示第j个供应商可以提供第k种货物b[j][k]单位。
再给出k个n*m的矩阵,格子c[k][i][j]表示第k种货物由j供应商提供给客户i的话,每单位运费为c[k][i][j]。
问最小费用。
分析:
刚开始时,虽然考虑到每种货物其实是不相关的,但是想到在跑费用流时应该没多大影响,所以直接建图,跑最小费用流,TLE了。。。
后来对于每种货物单独来考虑,即建图之后跑一次最小费用流,进行k次求费用流之后,判断总流是否等于需求的货物数量。这样建图,节点数明显减少了很多,实际效果非常明显。
#include <set> #include <map> #include <list> #include <cmath> #include <queue> #include <stack> #include <string> #include <vector> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; typedef unsigned long long ull; #define debug puts("here") #define rep(i,n) for(int i=0;i<n;i++) #define rep1(i,n) for(int i=1;i<=n;i++) #define REP(i,a,b) for(int i=a;i<=b;i++) #define foreach(i,vec) for(unsigned i=0;i<vec.size();i++) #define pb push_back #define RD(n) scanf("%d",&n) #define RD2(x,y) scanf("%d%d",&x,&y) #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define RD4(x,y,z,w) scanf("%d%d%d%d",&x,&y,&z,&w) #define All(vec) vec.begin(),vec.end() #define MP make_pair #define PII pair<int,int> #define PQ priority_queue #define cmax(x,y) x = max(x,y) #define cmin(x,y) x = min(x,y) #define Clear(x) memset(x,0,sizeof(x)) /* #pragma comment(linker, "/STACK:1024000000,1024000000") int size = 256 << 20; // 256MB char *p = (char*)malloc(size) + size; __asm__("movl %0, %%esp\n" :: "r"(p) ); */ char IN; inline void Int(int &x){ while(!isdigit(IN=getchar())); x = IN-'0'; while(isdigit(IN=getchar())) x = x*10+IN-'0'; } /******** program ********************/ const int MAXN = 205; const int MAXM = 100005; const int INF = 1e9; const int X = 52; int pre[MAXN],dis[MAXN]; int po[MAXN],tol; bool use[MAXN]; int q[MAXM],head,tail; int n,m,vs,vt,ans; int a[X][X],b[X][X],c[X][X][X]; int kk,flow; struct node{ int y,f,cost,next; }edge[MAXM]; void Add(int x,int y,int f,int cost){ edge[++tol].y = y; edge[tol].f = f; edge[tol].cost = cost; edge[tol].next = po[x]; po[x] = tol; } void add(int x,int y,int f,int cost){ Add(x,y,f,cost); Add(y,x,0,-cost); } bool spfa(){ memset(use,false,sizeof(use)); rep1(i,vt) dis[i] = INF; dis[vs] = 0; head = tail = 0; q[tail++] = vs; pre[vs] = 0; while(head<tail){ int x = q[head++]; use[x] = false; for(int i=po[x];i;i=edge[i].next){ int y = edge[i].y; if(edge[i].f>0&&edge[i].cost+dis[x]<dis[y]){ dis[y] = dis[x]+edge[i].cost; pre[y] = i; if(!use[y]){ use[y] = true; q[tail++] = y; } } } } if(dis[vt]==INF) return false; int aug = INF; for(int i=pre[vt];i;i=pre[edge[i^1].y]) aug = min(aug,edge[i].f); for(int i=pre[vt];i;i=pre[edge[i^1].y]){ edge[i].f -= aug; edge[i^1].f += aug; } ans += dis[vt]*aug; return true; } inline void fareFlow(int k){ Clear(po); tol = 1; vs = MAXN-3; vt = vs+1; rep1(i,n)if(a[i][k]) add( vs,i,a[i][k],0 ); rep1(j,m)if(b[j][k]){ add( j+n,vt,b[j][k],0 ); rep1(i,n) add(i,j+n,b[j][k],c[k][i][j]); } while(spfa()) ; for(int i=po[vt];i;i=edge[i].next) if(edge[i].f>0) flow += edge[i].f; } int main(){ #ifndef ONLINE_JUDGE freopen("sum.in","r",stdin); //freopen("sum.out","w",stdout); #endif while(true){ Int(n);Int(m);Int(kk); if(!n&&!m&&!kk)return 0; int tot = 0; rep1(i,n) rep1(k,kk){ Int(a[i][k]); tot += a[i][k]; } rep1(j,m) rep1(k,kk) Int(b[j][k]); rep1(k,kk) rep1(i,n) rep1(j,m) Int(c[k][i][j]); flow = 0; ans = 0; rep1(k,kk) fareFlow(k); printf("%d\n",tot==flow?ans:-1); } return 0; }