链接:http://poj.org/problem?id=2516
题意:有k种货物,n个客户对每种货物有一定需求量,有m个仓库。每一个仓库里有一定数量的k种货物。然后k个n*m的矩阵,告诉从各个仓库到各个客户位置运送单位第k种货物所需的运费。问满足全部客户需求的最小费用,如满足不了全部客户,则输出-1。
思路:题目有点绕。只是多看看也就理解了。这道题算是最小费用最大流的入门题吧,建图非常easy能想到,主要是存在k种货物。每条货物都要建一条路,同一时候处理起来不好写。并且路径也较多。只是能够对每种货物分开来算。数据比較小。给了4000ms,不会超时。对每一个n*m矩阵,对于此时的货物建图。把最小费用累加起来。
假设有一种货物没法满足全部客户。即网络最大流不等于客户需求之和,则输出-1。
建图:对于每种货物单独建图。一个超级源点连向每一个客户。弧为客户对当前这样的货物的需求量,权为0。每一个仓库连向超级汇点,弧为仓库中当前这样的货物的储存量,权为0。对于n*m的矩阵,相应的客户连向相应的仓库,弧为INF,权为运送单位货物的花费。
这样的建图方式比較好想,之前也做过几道题是一样的思路。
#include<cstring> #include<string> #include<fstream> #include<iostream> #include<iomanip> #include<cstdio> #include<cctype> #include<algorithm> #include<queue> #include<map> #include<set> #include<vector> #include<stack> #include<ctime> #include<cstdlib> #include<functional> #include<cmath> using namespace std; #define PI acos(-1.0) #define MAXN 500100 #define eps 1e-7 #define INF 0x7FFFFFFF #define LLINF 0x7FFFFFFFFFFFFFFF #define seed 131 #define mod 1000000007 #define ll long long #define ull unsigned ll #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 struct node{ int u,v,w,cost,next; }edge[MAXN]; int head[150],dist[150],pree[150],vis[150]; int n,m,k,cnt,src,sink,ans; void add_edge(int a,int b,int c,int d){ edge[cnt].v = b; edge[cnt].w = c; edge[cnt].cost = d; edge[cnt].next = head[a]; head[a] = cnt++; } bool spfa(){ int i,j; queue<int>q; q.push(src); memset(vis,0,sizeof(vis)); for(i=0;i<=n+m+2;i++) dist[i] = INF; dist[src] = 0; vis[src] = 1; while(!q.empty()){ int u = q.front(); q.pop(); vis[u] = 0; for(i=head[u];i!=-1;i=edge[i].next){ if(edge[i].w&&dist[u]!=INF&&dist[u]+edge[i].cost<dist[edge[i].v]){ dist[edge[i].v] = dist[u] + edge[i].cost; pree[edge[i].v] = i; if(!vis[edge[i].v]){ vis[edge[i].v] = 1; q.push(edge[i].v); } } } } // for(i=0;i<=n+m+2;i++){ // cout<<dist[i]<<endl; // } // cout<<endl<<endl; if(dist[sink]<INF) return true; return false; } int augment(){ int i,j; int delta = INF; for(i=sink;i!=src;i=edge[j^1].v){ j = pree[i]; delta = min(delta,edge[j].w); } for(i=sink;i!=src;i=edge[j^1].v){ j = pree[i]; edge[j].w -= delta; edge[j^1].w += delta; ans += edge[j].cost * delta; } return delta; } int ntok[60][60],ktom[60][60]; int main(){ int i,j,k; int a,b,c,sum; while(scanf("%d%d%d",&n,&m,&k),n||m||k){ ans = 0; for(i=1;i<=n;i++){ for(j=1;j<=k;j++){ scanf("%d",&ntok[i][j]); } } for(i=1;i<=m;i++){ for(j=1;j<=k;j++){ scanf("%d",&ktom[i][j]); } } src = n + m + 2; sink = n + m + 1; int ii; int flag = 0; for(i=1;i<=k;i++){ memset(head,-1,sizeof(head)); cnt = 0; sum = 0; int flow = 0; for(ii=1;ii<=n;ii++){ for(j=1;j<=m;j++){ scanf("%d",&a); add_edge(ii,j+n,INF,a); add_edge(j+n,ii,0,-a); } } if(flag) continue; for(ii=1;ii<=n;ii++){ add_edge(src,ii,ntok[ii][i],0); add_edge(ii,src,0,0); sum += ntok[ii][i]; } for(ii=1;ii<=m;ii++){ add_edge(ii+n,sink,ktom[ii][i],0); add_edge(sink,ii+n,0,0); } while(spfa()){ flow += augment(); } if(flow!=sum) flag = 1; } if(flag) puts("-1"); else printf("%d ",ans); } return 0; }