##吐槽

  ​ 好吧这个是真的很妙qwq用来解方程组的网络流嗯不能更清真


正题

首先是大概描述

  ​ 当一个方程组中所有的方程相加之后可以把所有的变量都消掉(也就是所有变量都出现一正一负可以抵消掉),我们会发现这个其实很像网络流中的流量平衡(正负一个看做流入一个看做流出)。我们可以将每条式子都看做一个点,方程中的常数就是限制方程成立的容量,这样我们就可以跑最大流来求出这个方程组的解了(如果说有一些别的限制条件什么满足×××最小或者最大啊之类的那就跑费用流就好)

这听起来很玄妙

  ​ 然而其实。。拿一道题来说事会更加直观一点。。

bzoj1061 志愿者招募

  ​ 我们设第\(i\)类志愿者的人数为\(x_i\),每个志愿者的费用为\(v_i\),第\(j\)天雇佣的人数为\(p_j\),那么我们可以把每天的雇佣人数写成一个不等式,为了方便表述这里给几个具体的数好一点

  ​ 天数4,\(p =\){\(2,3,4,5\)},总共有5类志愿者如下表

1 2 3 4 5
时间 1-1 1-2 2-3 3-3 3-4
费用 3 4 5 6 7

  ​ 那么我们可以列出式子:

\[\begin{aligned}
&p_1 = x_1+x_2>=2\\
&p_2=x_1+x_3>=3\\
&p_3=x_3+x_4+x_5>=4\\
&p_4=x_5>=5\\
\end{aligned}
\]

  ​ 为了把不等式转成等式,我们可以对每个式子添加一个辅助变量\(y_i\),注意\(y_i\)是有范围的(在不同的题目里面会有不同的限制,但是在这题里面比较直接就是\(y_i>=0\),\(y_i\)的范围会影响到后面建图的时候的边的容量),那么我们可以把式子转化成这样:

\[\begin{aligned}
&p_0=0\\
&p_1=x_1+x_2-y_1=2\\
&p_2=x_1+x_3-y_2=3\\
&p_3=x_3+x_4+x_5-y_3=4\\
&p_4=x_5-y_4=5\\
&p_5=0\\
\end{aligned}
\]

  ​ 为什么要在一前一后加多两条式子呢?因为这样以后,我们每次用第\(i+1\)条式子减去第\(i\)条式子,就可以得到这样的东西:

\[\begin{aligned}
&x_1+x_2-y_1=2&(p_1-p_0)\\
&x_3-x_2+y_1-y_2=1&(p_2-p_1)\\
&x_4+x_5-x_1+y_2-y_3=1&(p_3-p_2)\\
&-x_3-x_4+y_3-y_4=1&(p_4-p_3)\\
&-x_5+y_4=-5&(p_5-p_4)\\
\end{aligned}
\]

  ​ 现在观察一下这些式子,每个变量都出现了两次,一次为正一次为负,刚好可以抵消,而且所有等式的右边和为0,我们再移下项,变成这样(为了更加方便后面的建图说明):

\[\begin{aligned}
&-x_1-x_2+y_1+2=0\\
&-x_3-x_2-y_1+y_2+1=0\\
&-x_4-x_5+x_1-y_2+y_3+1=0\\
&x_3+x_4-y_3+y_4+1=0\\
&x_5-y_4-5=0\\
\end{aligned}
\]

  ​ 那么接下来先说一下如何建图,后面再解释为什么:

  • 将第\(i\)个等式看做图中编号为\(i\)的点,然后再添加两个点\(vs\)和\(vt\)作为源点和汇点

  • 对于一个等式\(i\)中的常数项\(c\),如果是非负整数,那么从源点\(vs\)连一条容量为\(c\)费用为\(0\)的有向边到\(i\)

    如果是负整数,那么从\(i\)连一条容量为\(abs(c)\)费用为\(0\)的有向边到汇点\(vt\)

  • 对于一个等式\(i\)中的变量\(x_i\),如果\(x_i\)在等式\(j\)中出现,且在\(i\)和\(j\)中符号相反,那么从符号为负的等式连一条容量为\(\infty\)费用为\(v_i\)的有向边到符号为正的等式

  ​ (注意,这里的容量应该为\(x_i\)的上限,这题里面是只要求\(x_i>=0\)即可所以是\(\infty\))

  • 对于一个等式\(i\)中的变量\(y_i\),如果\(y_i\)在等式\(j\)中出现,且在\(i\)和\(j\)中符号相反,那么从符号为负的等式连一条容量为\(\infty\)费用为\(0\)的有向边到符号为正的等式

  ​ (同样的,这里的容量应该为\(y_i\)的上限,这题里面也是恰好\(y_i>=0\)所以是\(\infty\))

  ​ 建完图之后,跑一遍最小费用最大流,\(ans\)就是\(vs\)到\(vt\)的最小费用


  ​ 怎么去理解呢?

  ​ 我们看回上面的等式,每个等式的左边都是几个变量和一个常数相加,右边都是0,会发现其实就像网络流中的除了源点和汇点以外其他的点都满足流量平衡(流进多少流出多少)

  ​ 那么,我们就可以把一个式子中所有正的变量理解为流入的流量,负的变量理解为流出的流量,而正常数可以理解为来自源点的流量(一开始就流过来的一定有的),负的常数则是流向汇点的流量,所以就可以按照这个思路来构建这样的一个网络流模型啦,从源点到汇点的网络最大流就可以满足所有的等式

  ​ 同时,这题还要求\(\sum\limits_{i=1}^{m}x_i*v_i\)最小,其实就是一个附加条件,那就给\(x\)变量对应的边上加上权值然后跑最小费用最大流即可ovo


  ​ 代码的话大概是这样的,顺便吐槽一句bzoj这题的数据好像有点弱啊。。第一次交上去的时候反向边两个都建成tot+1了结果还要过了。。qwq

  ​ (其实就是说下面的代码可能还是有bug欢迎纠错qwq)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define ll long long
#define inf 1000000
using namespace std;
const int N=1010;
const int M=10010;
struct xxx{
int y,next,r,op,c;
}a[M*10];
queue<int> q;
int h[N],X[N];
int pre[100010],mn[100010],pred[100010];
ll d[N];
ll ans;
bool vis[N];
int n,m,vs,vt,tot;
int add(int x,int y,int r,int c);
int spfa(); int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
int l,r,c,tmp;
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i) scanf("%d",X+i);
vs=0,vt=n+2;
memset(h,-1,sizeof(h));
for (int i=2;i<=n+1;++i) add(i,i-1,inf,0);
for (int i=1;i<=m;++i){
scanf("%d%d%d",&l,&r,&c);
add(l,r+1,inf,c);
}
for (int i=1;i<=n+1;++i){
tmp=X[i]-X[i-1];
if (tmp>0) add(vs,i,tmp,0);
if (tmp<0) add(i,vt,-tmp,0);
}
ans=0;
while (spfa());
printf("%lld\n",ans);
} int add(int x,int y,int r,int c){
a[++tot].y=y; a[tot].next=h[x]; h[x]=tot; a[tot].r=r; a[tot].op=tot+1; a[tot].c=c;
a[++tot].y=x; a[tot].next=h[y]; h[y]=tot; a[tot].r=0; a[tot].op=tot-1; a[tot].c=-c;
} int spfa(){
while (!q.empty()) q.pop();
for (int i=vs;i<=vt;++i) d[i]=inf,vis[i]=false,mn[i]=inf;
q.push(vs); vis[vs]=1; d[vs]=0;
mn[vs]=inf; pre[vs]=-1; pred[vs]=-1;
int v,u;
while (!q.empty()){
v=q.front(); q.pop();
for (int i=h[v];i!=-1;i=a[i].next){
u=a[i].y;
if (!a[i].r) continue;
if (d[u]>d[v]+a[i].c){
pre[u]=i; pred[u]=v;
mn[u]=min(mn[v],a[i].r);
d[u]=d[v]+a[i].c;
if (!vis[u])
vis[u]=1,q.push(u);
}
}
vis[v]=false;
}
if (d[vt]==inf) return false;
ll flow=mn[vt];
ans+=flow*d[vt];
u=vt;
while (pre[u]!=-1){
a[pre[u]].r-=flow;
a[a[pre[u]].op].r+=flow;
u=pred[u];
}
return true;
}

【learning】一种奇妙的网络流建模方式的更多相关文章

  1. 一种工业级系统交互建模工具的应用--EventStudio System Designer

    一种工业级系统交互建模工具的应用 [摘要] 本文以探索如何维护大规模复杂系统交互设计模型为目的,以EventHelix公司的商业付费软件EventStudio System Designer为建模工具 ...

  2. 【转】Verilog HDL常用建模方式——《Verilog与数字ASIC设计基础》读书笔记(四)

    Verilog HDL常用建模方式——<Verilog与数字ASIC设计基础>读书笔记(四) Verilog HDL的基本功能之一是描述可综合的硬件逻辑电路.所谓综合(Synthesis) ...

  3. 构建“元宇宙”,有哪些3D建模方式?

    "沉浸.3D世界.虚拟社交.虚拟购物",最近"元宇宙"的概念特别火.人们畅想通过AR/VR以及其他互联网技术,把现实世界的楼房街道.天气温度.人际关系等投射到虚 ...

  4. ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式

    由于ASP.NET Core应用是一个同时处理多个请求的服务器应用,所以在处理某个请求过程中抛出的异常并不会导致整个应用的终止.出于安全方面的考量,为了避免敏感信息的外泄,客户端在默认的情况下并不会得 ...

  5. UVA 11082 矩阵解压(网络流建模)

    矩阵解压 紫书P374 建模真的是挺难的,如果直接给我这题,我是想不到用网络流的,所以还应多做网路流建模,学会如何转化成网络流 还有,现在用的EK算法是比较慢的,还应去看看Dnic和ISAP,并且理解 ...

  6. Js之Dom学习-三种获取页面元素的方式、事件、innerText和innerHTML的异同

    一.三种获取页面元素的方式: getElementById:通过id来获取 <body> <input type="text" value="请输入一个 ...

  7. javascript一种新的对象创建方式-Object.create()

    1.Object.create() 是什么? Object.create(proto [, propertiesObject ]) 是E5中提出的一种新的对象创建方式,第一个参数是要继承的原型,如果不 ...

  8. 转: .NET MVC3 几种返回 JSON 对象的方式和注意事项

    .NET MVC3 几种返回 JSON 对象的方式和注意事项 转自:http://blog.csdn.net/xxj_jing/article/details/7382589 引言在用 .NET MV ...

  9. sql有几种删除表数据的方式

    有几种删除表数据的方式? truncate.delete和drop都可以删除数据. TRUNCATE TABLE删除表中的所有行,而不记录单个行删除操作. TRUNCATE TABLE 与没有 WHE ...

随机推荐

  1. centos 6.8 下安装redmine(缺陷跟踪系统)

    一.实验环境 centos6.8 64位 所需安装包: ruby-2.3.4.tar.gz.rubygems-1.8.25.tgz.redmine-2.3.2.tar.gz 二.安装步骤 1.安装必要 ...

  2. C++11 标准库也有坑(time-chrono)

    恰巧今天调试程序遇到时间戳问题, 于是又搜了搜关于取时间戳,以及时间戳转字符串的问题, 因为 time()   只能取到秒(win和linux) 想试试看能不能找到 至少可以取到毫秒的, 于是, 就找 ...

  3. 【Unity3D技术文档翻译】第1.8篇 AssetBundles 问题及解决方法

    上一章:[Unity3D技术文档翻译]第1.7篇 AssetBundles 补丁更新 本章原文所在章节:[Unity Manual]→[Working in Unity]→[Advanced Deve ...

  4. Windows Server 2016-图形化备份域控制器

    上边几章节我们补充了有关Windows Server 2016系统层面的相关内容,本章切回Active Directory正题,继续围绕AD域相关内容进行不断梳理补充.Windows Server B ...

  5. 《android开发艺术探索》读书笔记(十)--Android的消息机制

    接上篇<android开发艺术探索>读书笔记(九)--四大组件 No1: 消息队列MessageQueue的内部存储结构并不是真正的队列,而是采用单链表的数据结构来存储消息列表,因为单链表 ...

  6. Java遍历文件目录

    函数介绍 File[] listFiles():返回当前文件的子目录或子文件的文件数组. 遍历目录 调用listFiles()即可得文件的子目录和子文件,如果存在子目录,那么子目录需要再次调用list ...

  7. (2018干货系列五)最新UI设计学习路线整合

    怎么学UI全链路设计 全链路设计师是参与整个商业链条,为每个会影响用户体验的地方提供设计的可解决方案,最后既满足了商业目标,又提升了产品的用户体验和设计质量,与平面设计.UI设计彻底区分开来,是真正的 ...

  8. Maven就是这么简单

    什么是Maven Maven是一个采用纯Java编写的开源项目管理工具, Maven采用了一种被称之为Project Object Model (POM)概念来管理项目,所有的项目配置信息都被定义在一 ...

  9. ARM开发软件ADS教程

    ARM开发软件ADS教程 ADS(ARM Developer Suite)是ARM公司推出ARM集成开发环境,操作简单方便,获得广大开发人员的青睐.下面使用ADS v1.2做一个实例教程,帮助大家学会 ...

  10. VC下ffmpeg例程调试报错处理

    tools/options/directories/include files  添加ffmpeg头文件所在路径 tools/options/directories/library files  添加 ...