POJ - 2516 Minimum Cost(最小费用最大流)
題目鏈接:點(diǎn)擊查看
題目大意:給出n個(gè)買家,m個(gè)貨點(diǎn),以及k種貨物,接下來(lái)按照順序依次給出一個(gè)n*k的矩陣,表示每個(gè)買家對(duì)于每種貨物的需求,一個(gè)m*k的矩陣,表示每個(gè)貨點(diǎn)能供給貨物的數(shù)量,k個(gè)n*m的矩陣,表示對(duì)于每種貨物,買家從貨點(diǎn)進(jìn)貨所需要的花費(fèi),現(xiàn)在求在滿足所有買家需求的情況下,進(jìn)貨花費(fèi)的最小值
題目分析:一開始看到這個(gè)題目的第一反應(yīng)就是拆點(diǎn),但后來(lái)想了想不太行,因?yàn)辄c(diǎn)太多了,對(duì)于每個(gè)買家和每個(gè)貨點(diǎn),都有流量的限制,所以如果想要拆點(diǎn)的話,每個(gè)買家和貨點(diǎn)都需要重新拆成k個(gè)點(diǎn),用于限流才行,這樣一來(lái)點(diǎn)數(shù)就是2500+2500,邊數(shù)也到達(dá)了6e7的級(jí)別,數(shù)據(jù)量太大了,時(shí)間復(fù)雜度頂不住。后來(lái)去網(wǎng)上看了題解發(fā)現(xiàn),其實(shí)可以直接跑k次最小費(fèi)用最大流,因?yàn)閷?duì)于k種貨物都是相對(duì)獨(dú)立的,拿掉貨物的種類之后,剩下的就是買家與貨點(diǎn)連邊了,在此之前還可以特判一下能否完成每個(gè)買家的需求提前剪枝,我們可以另外多開兩個(gè)數(shù)組記錄對(duì)于每種貨物而言的需求數(shù)和供給數(shù),若需求數(shù)大于供給數(shù),那么直接輸出-1就好了,滿足條件再繼續(xù)跑費(fèi)用流,關(guān)于建邊,是對(duì)于每種貨物分別建邊:
建完圖后跑k次最小費(fèi)用最大流就是答案了
代碼:
#include<iostream> #include<cstdlib> #include<string> #include<cstring> #include<cstdio> #include<algorithm> #include<climits> #include<cmath> #include<cctype> #include<stack> #include<queue> #include<list> #include<vector> #include<set> #include<map> #include<sstream> using namespace std;typedef long long LL;const int inf=0x3f3f3f3f;const int N=110;//點(diǎn)const int M=N*N;//邊struct Edge {int to,w,cost,next; }edge[M];int head[N],cnt;void addedge(int u,int v,int w,int cost) {edge[cnt].to=v;edge[cnt].w=w;edge[cnt].cost=cost;edge[cnt].next=head[u];head[u]=cnt++;edge[cnt].to=u;edge[cnt].w=0;edge[cnt].cost=-cost;edge[cnt].next=head[v];head[v]=cnt++; }int d[N],incf[N],pre[N];bool vis[N];bool spfa(int s,int t) {memset(d,inf,sizeof(d));memset(vis,false,sizeof(vis));memset(pre,-1,sizeof(pre));queue<int>q;q.push(s);vis[s]=true;incf[s]=inf;d[s]=0;while(!q.empty()){int u=q.front();q.pop();vis[u]=false;for(int i=head[u];i!=-1;i=edge[i].next){int v=edge[i].to;int w=edge[i].w;int cost=edge[i].cost;if(!w)continue;if(d[v]>d[u]+cost){d[v]=d[u]+cost;pre[v]=i;incf[v]=min(incf[u],w);if(!vis[v]){vis[v]=true;q.push(v);}}}}return pre[t]!=-1; }int update(int s,int t) {int x=t;while(x!=s){int i=pre[x];edge[i].w-=incf[t];edge[i^1].w+=incf[t];x=edge[i^1].to;}return d[t]*incf[t]; }void init() {memset(head,-1,sizeof(head));cnt=0; }int solve(int st,int ed) {int ans=0;while(spfa(st,ed))ans+=update(st,ed);return ans; }int a[55][55],b[55][55],c[55][55][55],f[55],e[55];bool check(int k) {for(int i=1;i<=k;i++)if(f[i]<e[i])return false;return true; }int main() { // freopen("input.txt","r",stdin); // ios::sync_with_stdio(false);int n,m,k;while(scanf("%d%d%d",&n,&m,&k)!=EOF&&n+m+k){memset(f,0,sizeof(f));memset(e,0,sizeof(e));int st=N-1,ed=st-1;for(int i=1;i<=n;i++)//a[i][j]:第i個(gè)買家需要第j種貨物的個(gè)數(shù) for(int j=1;j<=k;j++){scanf("%d",&a[i][j]);e[j]+=a[i][j];//e[i]:第i種貨物的總數(shù)(買家購(gòu)入) }for(int i=1;i<=m;i++)//b[i][j]:第i和貨點(diǎn)有第j種貨物的個(gè)數(shù) for(int j=1;j<=k;j++){scanf("%d",&b[i][j]);f[j]+=b[i][j];//d[i]:第i種貨物的總數(shù)(貨點(diǎn)提供)}for(int i=1;i<=k;i++)//c[i][j][k]:第k種貨物,第i個(gè)買家從第j個(gè)貨點(diǎn)買,的花費(fèi) for(int j=1;j<=n;j++)for(int t=1;t<=m;t++)scanf("%d",&c[i][j][t]);if(!check(k)){printf("-1\n");continue;}bool flag=true;int ans=0;for(int t=1;t<=k;t++)//枚舉每一種貨物,對(duì)于每一種貨物單獨(dú)跑費(fèi)用流 {init();int st=N-1,ed=st-1;for(int i=1;i<=n;i++)//枚舉買家{addedge(st,i,a[i][t],0);for(int j=1;j<=m;j++)//枚舉貨點(diǎn)addedge(i,j+n,inf,c[t][i][j]);}for(int i=1;i<=m;i++)addedge(i+n,ed,b[i][t],0);ans+=solve(st,ed);}printf("%d\n",ans);}return 0; }?
總結(jié)
以上是生活随笔為你收集整理的POJ - 2516 Minimum Cost(最小费用最大流)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: POJ - 1087 A Plug fo
- 下一篇: CodeForces - 1245C C