[网络流24题(5/24)] 分配问题(最小费用最大流)
时间:2019-08-19
本文章向大家介绍[网络流24题(5/24)] 分配问题(最小费用最大流),主要包括[网络流24题(5/24)] 分配问题(最小费用最大流)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
分析:
非常经典的费用流的模型吧,也可以通过二分图最大匹配去做,但是鉴于二分图最大匹配的算法存在一定的局限性,故还是学一学较为通用的费用流的做法。
这道题目中本质上要讨论的问题跟运输问题,运输问题是一致的。
因为考虑到每个人只能被分配到一种货物,每种货物只能被一个人所分配,因此,我们不妨用流量将他们限流。
我们创建一个超级源地\(sp\),将\(sp\)跟每个人连一条流量为\(1\),费用为\(0\)的边。
同时我们创建一个超级汇点\(ep\),将每一种货物跟\(ep\)都连一条流量为\(1\),费用为\(0\)的边。
同时,对于每一个人和货物,我们对他们连一条流量为无穷的边。
因为每个人只能从超级源点获取最多\(1\)点的流量,每种货物只能向超级汇点传送最多\(1\)点的流量,因此当这个图满流时,能够保证每个人一定会配对最多一个货物,即达到我们限流的要求。
而如果我们需要求解最小花费,我们只需要将人和货物的边加上的费用取\(val_{ij}\),最后在这张图上跑最小费用最大流后最小费用即为答案。
而如果我们需要求解最大花费,我们只需要将人和货物的边加上的费用取相反数\(-val_{ij}\),最后在这张图上跑最小费用最大流后最小费用的相反数即为答案。
代码:
#include <bits/stdc++.h>
#define maxn 4050
using namespace std;
struct Node{
int to,next,val,cost;
}q[maxn<<1];
int head[maxn],cnt=0;
int dis[maxn],vis[maxn],sp,ep,maxflow,cost;
int n,num[maxn][maxn];
const int INF=0x3f3f3f3f;
void init(){
memset(head,-1,sizeof(head));
cnt=2;
maxflow=cost=0;
}
void addedge(int from,int to,int val,int cost){
q[cnt].to=to;
q[cnt].next=head[from];
q[cnt].val=val;
q[cnt].cost=cost;
head[from]=cnt++;
}
void add_edge(int from,int to,int val,int cost){
addedge(from,to,val,cost);
addedge(to,from,0,-cost);
}
bool spfa(){
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[sp]=0;
vis[sp]=1;
queue<int>que;
que.push(sp);
while(!que.empty()){
int x=que.front();
que.pop();
vis[x]=0;
for(int i=head[x];i!=-1;i=q[i].next){
int to=q[i].to;
if(dis[to]>dis[x]+q[i].cost&&q[i].val){
dis[to]=dis[x]+q[i].cost;
if(!vis[to]){
que.push(to);
vis[to]=1;
}
}
}
}
return dis[ep]!=0x3f3f3f3f;
}
int dfs(int x,int flow){
if(x==ep){
vis[ep]=1;
maxflow+=flow;
return flow;
}//可以到达t,加流
int used=0;//该条路径可用流量
vis[x]=1;
for(int i=head[x];i!=-1;i=q[i].next){
int to=q[i].to;
if((vis[to]==0||to==ep)&&q[i].val!=0&&dis[to]==dis[x]+q[i].cost){
int minflow=dfs(to,min(flow-used,q[i].val));
if(minflow!=0){
cost+=q[i].cost*minflow;
q[i].val-=minflow;
q[i^1].val+=minflow;
used+=minflow;
}
//可以到达t,加费用,扣流量
if(used==flow)break;
}
}
return used;
}int mincostmaxflow(){
while(spfa()){
vis[ep]=1;
while(vis[ep]){
memset(vis,0,sizeof(vis));
dfs(sp,INF);
}
}
return maxflow;
}
int main()
{
scanf("%d",&n);
init();
sp=2*n+1,ep=2*n+2;
for(int i=1;i<=n;i++){
add_edge(sp,i,1,0);
add_edge(i+n,ep,1,0);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&num[i][j]);
add_edge(i,j+n,INF,num[i][j]);
}
}
mincostmaxflow();
printf("%d\n",cost);
init();
for(int i=1;i<=n;i++){
add_edge(sp,i,1,0);
add_edge(i+n,ep,1,0);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
add_edge(i,j+n,INF,-num[i][j]);
}
}
mincostmaxflow();
printf("%d\n",-cost);
return 0;
}
原文地址:https://www.cnblogs.com/Chen-Jr/p/11379351.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法