Time Limit: 4000MS | Memory Limit: 65536K | |
Total Submissions: 9392 | Accepted: 3108 |
Description
Input
Output
Sample Input
1 3 3 1 1 1 0 1 1 1 2 2 1 0 1 1 2 3 1 1 1 2 1 1 1 1 1 3 2 20 0 0 0
Sample Output
4 -1
****************************************************************
题目大意:有n个订单,m个仓库和k种物品。每个订单上有k种物品每种物品的需求,每个仓库里有k种物品的数量,还给出物品i从仓库j送到订单h所需要的花费。问满足订单要求的所需的最小花费。
解题思路:对每种物品分别计算。拆点+最小边权匹配。可怜我visy的位置写错,TLE了几次。
#include <stdio.h> #include <string.h> #include <vector> #define N 55 #define INF 0x3f3f3f3f using namespace std; int tn[N][N],tm[N][N],tk[N][N][N]; int sum1[N],sum2[N]; int n,m,k,lack,limx,limy; int gra[155][155],ix[1550],iy[155]; int lx[155],ly[155],mat[155]; int visx[155],visy[155]; int dfs(int x) { visx[x]=1; for(int y=1;y<=limy;y++) { if(visx[mat[y]])continue; int t=lx[x]+ly[y]-gra[x][y]; if(t==0) { visy[y]=1; if(!mat[y]||dfs(mat[y])) { mat[y]=x; return 1; } } else lack=min(lack,t); } return 0; } void re(void) { 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",&tn[i][j]),sum1[j]+=tn[i][j]; for(int i=1;i<=m;i++) for(int j=1;j<=k;j++) scanf("%d",&tm[i][j]),sum2[j]+=tm[i][j]; for(int i=1;i<=k;i++) for(int j=1;j<=n;j++) for(int h=1;h<=m;h++) scanf("%d",&tk[i][j][h]); } void run(void) { int ans=0; for(int h=1;h<=k;h++) { int id=0; limx=sum1[h]; limy=sum2[h]; if(limx>limy) { puts("-1"); return ; } for(int i=1;i<=n;i++) for(int j=1;j<=tn[i][h];j++) ix[++id]=i; id=0; for(int i=1;i<=m;i++) for(int j=1;j<=tm[i][h];j++) iy[++id]=i; memset(lx,0,sizeof(lx)); memset(ly,0,sizeof(ly)); for(int i=1;i<=limx;i++) for(int j=1;j<=limy;j++) { gra[i][j]=1000-tk[h][ix[i]][iy[j]]; lx[i]=max(lx[i],gra[i][j]); } memset(mat,0,sizeof(mat)); for(int i=1;i<=limx;i++) { memset(visx,0,sizeof(visx)); memset(visy,0,sizeof(visy)); lack=INF; while(!dfs(i)) { for(int j=1;j<=limx;j++) if(visx[j]) { lx[j]-=lack; visx[j]=0; } for(int j=1;j<=limy;j++) if(visy[j]) { ly[j]+=lack; visy[j]=0; } lack=INF; } } for(int i=1;i<=limy;i++) if(mat[i]) ans+=1000-gra[mat[i]][i]; } printf("%d\n",ans); } int main() { while(scanf("%d%d%d",&n,&m,&k)==3&&(n!=0||m!=0||k!=0)) { re(); run(); } return 0; }