Time Limit: 4000MS | Memory Limit: 65536K | |
Total Submissions: 13511 | Accepted: 4628 |
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
这一题的边有两个性质,
1 容量:供给-种类/需求-种类
2 价格: 供给-种类-需求
怎么想都想不到怎么保留这两种性质建边
看到小you的博客,可以分种类建图,恍然大悟
于是对每个种类分成两种边
1 源点->供给 需求->最终汇点 用于控制流量,价格为0
2 供给->需求 用于控制价格,流量为inf,
值得一提的是供给->需求是单向边,返回的边价格应该是负数,在这里卡了一次,还有每次流量应该是需求量
#include <cstdio> #include <vector> #include <queue> #include <cstring> using namespace std; const int maxn=52; const int maxm=52; const int maxk=52; const int maxnum=154; const int inf =0x7fffffff; int f[maxnum][maxnum];//s 151 t 152 int cons[maxk][maxnum]; int cost[maxk][maxnum][maxnum]; int e[maxnum][maxnum]; int len[maxnum]; const int sups=151,supt=152; int sum,n,m,k; int s1[maxk],s2[maxk];//s1 0-n-1 s2 n-n+m bool input(){ memset(cons,0,sizeof(cons)); memset(s1,0,sizeof(s1)); memset(s2,0,sizeof(s2)); sum=0; if(scanf("%d%d%d",&n,&m,&k)!=3)return false; if(n==0&&m==0&&k==0)return false; for(int i=0;i<n;i++){ int c; for(int j=0;j<k;j++){ scanf("%d",&c); cons[j][i]=c; s1[j]+=c; } } for(int i=n;i<n+m;i++){ int c; for(int j=0;j<k;j++){ scanf("%d",&c); cons[j][i]=c; s2[j]+=c; } } for(int i=0;i<k;i++){ for(int j=0;j<n;j++){ for(int ii=n;ii<n+m;ii++){ int c; scanf("%d",&c); cost[i][j][ii]=c;cost[i][ii][j]=-c; } } } for(int i=0;i<n;i++){ for(int j=n;j<n+m;j++){ e[i][j-n]=j; e[j][i]=i; e[i][m]=151; e[j][n]=152; e[151][i]=i; e[152][j-n]=j; } } fill(len,len+n,m+1); fill(len+n,len+n+m,n+1); len[151]=n; len[152]=m; return true; } void build(int kind){ memset(f,0,sizeof(f)); for(int i=0;i<n;i++)f[151][i]=cons[kind][i]; for(int i=n;i<n+m;i++)f[i][152]=cons[kind][i]; for(int i=0;i<n;i++){ for(int j=n;j<n+m;j++){ f[i][j]=inf; } } } int d[maxnum],pre[maxnum]; bool vis[maxnum]; queue<int >que; int mincostmaxflow(int s,int flow,int kind){ build(kind); int res=0; while(flow>0){ fill(d,d+154,inf); memset(vis,0,sizeof(vis)); d[s]=0; que.push(s); while(!que.empty()){ int fr=que.front();que.pop(); vis[fr]=false; for(int i=0;i<len[fr];i++){ int t=e[fr][i]; if(f[fr][t]>0&&d[t]>d[fr]+cost[kind][fr][t]){ d[t]=d[fr]+cost[kind][fr][t]; pre[t]=fr; if(!vis[t]){ que.push(t); vis[t]=true; } } } } if(d[supt]==inf)return -1; int sub=flow; for(int v=supt;v!=sups;v=pre[v]){ sub=min(sub,f[pre[v]][v]); } flow-=sub; res+=sub*d[supt]; for(int v=supt;v!=sups;v=pre[v]){ f[v][pre[v]]+=sub; f[pre[v]][v]-=sub; } } return res; } int main(){ while(input()){ int ans=0; bool sign=false; for(int i=0;i<k;i++){ if(s1[i]>s2[i]){printf("-1\n");sign=true;break;} } if(sign)continue; for(int i=0;i<k;i++){ int res=mincostmaxflow(151,s1[i],i); if(res==-1){printf("-1\n");sign=true;break;} ans+=res; } if(sign)continue; printf("%d\n",ans); } return 0; }