POJ-2516 Minimum Cost
阿新 • • 發佈:2018-11-10
一開始想拆點,用n*k個點和m*k個點匹配,求最小花費
然後就是5000個點的最小費用最大流演算法,妥妥的超時了
看了別人寫的,可以把每種商品分開單獨計算,每次就n+m個點的圖,算k次加起來
寫的時候有個地方沒注意,直接break,導致輸入偏差了,WA了好多次
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #include<queue> using namespace std; typedef long long ll; const int N=200+10; const int M=20000+10; const int INF=0x7f7f7f7f; struct Edge { int to,nxt,cap,flow,cost; }edge[M]; int tot,first[N]; void addedge(int u,int v,int w,int rw,int cost) { edge[tot].to=v;edge[tot].cap=w;edge[tot].flow=0; edge[tot].cost=cost;edge[tot].nxt=first[u];first[u]=tot++; edge[tot].to=u;edge[tot].cap=rw;edge[tot].flow=0; edge[tot].cost=-cost;edge[tot].nxt=first[v];first[v]=tot++; } void init() { tot=0; memset(first,-1,sizeof(first)); } int pre[N],dis[N]; bool vis[N]; bool spfa(int s,int t,int n) { queue<int> q; for(int i=0;i<n;i++) { dis[i]=INF; pre[i]=-1; vis[i]=false; } q.push(s); dis[s]=0; vis[s]=true; while(!q.empty()) { int u=q.front(); q.pop(); vis[u]=false; for(int i=first[u];i!=-1;i=edge[i].nxt) { int v=edge[i].to; if(edge[i].cap>edge[i].flow&&dis[u]+edge[i].cost<dis[v]) { 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 MCMF(int s,int t,int &cost,int n) { int flow=0; cost=0; while(spfa(s,t,n)) { 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; } int in[N][N]; int out[N][N]; int main() { int n,m,k; int a; while(~scanf("%d%d%d",&n,&m,&k)&&(n+m+k)) { for(int i=1;i<=n;i++) for(int j=1;j<=k;j++) scanf("%d",&in[i][j]); for(int i=1;i<=m;i++) for(int j=1;j<=k;j++) scanf("%d",&out[i][j]); bool flag=true; int ans=0; for(int w=1;w<=k;w++) { init(); int sum=0,sum0=0; for(int i=1;i<=n;i++) addedge(0,i,in[i][w],0,0),sum+=in[i][w]; for(int i=1;i<=m;i++) addedge(n+i,n+m+1,out[i][w],0,0),sum0+=out[i][w]; for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { scanf("%d",&a); addedge(i,n+j,INF,0,a); } if(sum>sum0||!flag) { flag=false; continue; //這裡寫成了break,WA好多次 } int cost; MCMF(0,n+m+1,cost,n+m+2); ans+=cost; } if(flag) printf("%d\n",ans); else printf("-1\n"); } return 0; }