poj2516——Minimum Cost

本文深入探讨了最小权值匹配算法的应用场景及其在解决特定问题中的实现细节。通过将需求方与供应方的需求和供给数量拆解为多个节点,构建了一个有效的匹配模型。文章详细解释了如何使用KM算法来寻找最小权值的最大匹配,并提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最小权值匹配!所谓最小权值匹配:即将左右两边的点配对,在最大匹配数的情况下,求最小权值!
关键在于建图:将每个店所要求的货物N,拆成N个点,同时supply的地方,所提供的货物n,也拆成n个点。--->套用最小权值匹配。

ps:对此题,最小权值匹配ms比最小费用最大流快!

#include<iostream> #include<cstdio> #include<cstring> #define maxn 55 using namespace std; int n,m,k; int order[maxn][maxn],supply[maxn][maxn],cost[maxn][maxn]; int lx[maxn*3],ly[maxn*3],my[maxn*3],slack[maxn*3]; bool vx[maxn*3],vy[maxn*3]; int topx,topy; int ans; int A[maxn*3],B[maxn*3],W[maxn*3][maxn*3]; bool dfs(int u) { int v,t; vx[u]=1; for(v=1;v<=topy;v++) { if(!vy[v]) { t=W[u][v]-lx[u]-ly[v]; if(t==0) { vy[v]=1; if(my[v]==-1||dfs(my[v])) { my[v]=u;return true; } } else slack[v]=slack[v]<t?slack[v]:t; } } return false; } void KM() { int i,j,min,d; for(i=1;i<=topx;i++) { min=10000; for(j=1;j<=topy;j++) if(W[i][j]<min) min=W[i][j]; lx[i]=min; } memset(ly,0,sizeof(ly)); memset(my,-1,sizeof(my)); for(i=1;i<=topx;i++) { memset(slack,127,sizeof(slack)); while(1) { memset(vx,0,sizeof(vx)); memset(vy,0,sizeof(vy)); if(dfs(i)) break; d=999999; for(j=1;j<=topy;j++) if(!vy[j]) d=d<slack[j]?d:slack[j]; for(j=1;j<=topx;j++) if(vx[j]) lx[j]+=d; for(j=1;j<=topy;j++) if(vy[j]) ly[j]-=d; } } for(i=1;i<=topy;i++) { if(my[i]!=-1) ans+=W[my[i]][i]; } } int main() { int i,j,t; bool flag; while(1) { cin>>n>>m>>k; int require,provide; if(n+m+k==0) break; ans=0; for(i=1;i<=n;i++) { for(j=1;j<=k;j++) cin>>order[i][j]; } for(i=1;i<=m;i++) for(j=1;j<=k;j++) cin>>supply[i][j]; flag=true; for(t=1;t<=k;t++) { for(i=1;i<=n;i++) for(j=1;j<=m;j++) cin>>cost[i][j]; provide=0;require=0; for(i=1;i<=n;i++) require+=order[i][t]; for(i=1;i<=m;i++) provide+=supply[i][t]; if(require>provide) flag=false; if(flag) { topx=0;topy=0; for(i=1;i<=n;i++) for(j=1;j<=order[i][t];j++) { A[++topx]=i; } for(i=1;i<=m;i++) for(j=1;j<=supply[i][t];j++) { B[++topy]=i; } for(i=1;i<=topx;i++) for(j=1;j<=topy;j++) W[i][j]=cost[A[i]][B[j]]; KM(); } } if(flag) cout<<ans<<endl; else cout<<-1<<endl; } return 0; }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值