pku 2516(最小费用最大流)

很烦的构图,起初想把每一个供应地的每一种物品都拆成一个点,不过MLE了。

之后看解题报告,因为每种物品互不影响,所以可以对每一种物品求一次费用流。

用need和offer数组存下每一个商店和供应地对每种物品的需求和供应量。

求之前可以判断一次是否有解,对每一种物品,求供和需的总和的大小,若有一种物品的需大于求,则无解,否则有解。

 

#include <iostream> #include <cstring> #include <queue> using namespace std; /* 最小费用最大流:visit[]记录点是否在队列中,pre[]保留节点的前驱 dis[]保存最短路径,net[][]为残留网络,cost[][]为耗费 s为源点,t为汇点 */ const int MAXN=105; const int inf=9999; bool visit[MAXN],answer; int pre[MAXN],dis[MAXN],net[MAXN][MAXN],cost[MAXN][MAXN]; int min_cost,max_flow; int total_cost,need[MAXN][MAXN],offer[MAXN][MAXN]; inline int min(int a,int b) { return a>b?b:a; } bool spfa(int &s,int &t) { queue<int> que; int tmp,k; memset(pre,-1,sizeof(pre)); memset(visit,false,sizeof(visit)); que.push(s); visit[s]=true; for(int i=s;i<=t;++i) dis[i]=inf; dis[s]=0; while(!que.empty()) { tmp=que.front(); que.pop(); visit[tmp]=false; for(int i=s;i<=t;++i) { k=dis[tmp]+cost[tmp][i]; if(net[tmp][i]>0 && dis[i]>k) { dis[i] = k; pre[i]=tmp; if(!visit[i]) { que.push(i); visit[i]=true; } } } } return dis[t] != inf; } void min_cost_max_flow(int &s,int &t) { int i,j,k,flow=inf; min_cost=0; max_flow=0; while(spfa(s,t)) { k=t; while(k!=s) //寻找流网络中的最小值 { flow=min(flow,net[pre[k]][k]); k=pre[k]; } k=t; min_cost+=dis[t]*flow; max_flow+=flow; while(k!=s) //更新残留网络 { net[pre[k]][k] -= flow; net[k][pre[k]] += flow; k=pre[k]; } } } void creat_G(int &n,int &m,int &k,int &s,int &t) //构图函数 { int sum,sum2; for(int i=1;i<=n;++i) for(int j=1;j<=k;++j) cin>>need[i][j]; for(int i=1;i<=m;++i) for(int j=1;j<=k;++j) cin>>offer[i][j]; for(int p=1;p<=k;++p) { sum=0; sum2=0; for(int i=1;i<=n;++i) sum+=need[i][p]; for(int i=1;i<=m;++i) sum2+=offer[i][p]; if(sum>sum2) { answer=false; break; } } for(int p=1;p<=k;++p) { memset(cost,0,sizeof(cost)); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) { cin>>cost[j][m+i]; cost[m+i][j]= -cost[j][m+i]; } if(!answer) continue; memset(net,0,sizeof(net)); for(int i=1;i<=n;++i) net[m+i][t]=need[i][p]; for(int i=1;i<=m;++i) net[s][i]=offer[i][p]; for(int i=1;i<=m;++i) for(int j=1+m;j<=m+n;++j) { net[i][j]=inf; } min_cost_max_flow(s,t); total_cost+=min_cost; } } int main() { int n,m,k,s,t; while(cin>>n>>m>>k && n+m+k) { s=0; t=n+m+1; answer=true; total_cost=0; creat_G(n,m,k,s,t); if(answer) cout<<total_cost<<endl; else cout<<-1<<endl; } return 0; }

你可能感兴趣的:(pku 2516(最小费用最大流))