zoukankan      html  css  js  c++  java
  • 网络流基础题六道

    好久没刷过网络流了,来刷几道题练练手。

    都比较基础,大佬们勿喷(

    1. P5039 [SHOI2010]最小生成树

    首先考虑第 (Lab) 条边一定出现在 MST 中的充要条件是什么:第 (Lab) 条边一定会出现在 MST 中,当且仅当所有权值 (le)(Lab) 条边的权值的边组成的子图中,第 (Lab) 条边的两个端点不在同一连通块中。

    这样一来思路就很显然了,把 (le)(Lab) 条边的权值的边拎出来建一张图,割掉第 (i) 条边意味着让这条边不出现在这张图中,代价显然是将这条边权值变到 (>Lab) 的权值的代价,即 (w_{Lab}-w_i+1),然后以 (Lab) 的两个端点为源和汇,跑最小割即最大流即可。

    2. P4452 [国家集训队]航班安排

    将每个航班拆成两个点,中间连容量 (1) 费用 (c) 的边,表示每个请求只能选一次。

    然后对于每个航班,如果从 (0) 机场出发飞往该机场的时间 (le) 其出发时间,就连一条源点到该点入点,容量为 (1),费用为 (0) 机场到该航班起点费用的相反数的边,同理如果一个航班能在 (T) 时间内赶回 (0) 机场,就连一条该点出点到汇点,容量为 (1),费用为该航班终点到 (0) 机场费用的相反数。对于每两个满足 (i) 的结束时间加上 (i) 终点到 (j) 起点所需时间 (le) (j) 的开始时间的两个航班 (i,j),连一条 (out_i o in_j),容量 (1),费用为 (i) 终点到 (j) 起点费用相反数的边。最后由于还有 (k) 架飞机的限制,就建一个超级源点,向源点连容量为 (k) 的边,然后最大费用最大流一波带走。

    3. P4177 [CEOI2008]order

    简单题,考虑这样建图:

    • 对于所有工作新建一个点 (p_i),并连一条 (S o p_i),容量 (x_i)​ 的边。
    • 对每个机器新建一个点 (q_i),并连一条 (q_i o T),容量 (y_i) 的边。
    • 对每个工作 (i) 需要的机器 (a_{i,j}),连一条 (p_i o q_{a_{i,j}}),容量 (b_{i,j}) 的边。

    然后跑最小割,(sumlimits_{i=1}^nx_i) 减去最小割的大小就是答案,正确性就按照集合划分模型的套路来即可。

    4. P3872 [TJOI2010]电影迷

    还是一道简单题,对于所有兴趣程度为正的电影 (i),连一条 (S o i),容量为 (x_i) 的边,对于所有兴趣程度为负的电影 (i),连一条 (i o T),容量为 (-x_i) 的边,然后对于所有依赖关系 ((u,v,w)),连一条 (u o v),容量为 (w) 的边,然后拿所有兴趣程度为正的电影的兴趣程度加上所有依赖关系里的 (w),减去最小割即最大流就是答案。正确性证明大概也是集合划分模型,我们将所有与 (S) 相连的电影看作被选择,与 (T) 相连的电影看作不被选择,那么所有兴趣程度为正的电影的兴趣程度加上所有依赖关系里的 (w),减去割的权值就是小 A 的体验值。

    5. P5295 [北京省选集训2019]图的难题

    这题还算有点意思(

    首先考虑一个非常显然的性质,如果 (mge 2n-1) 那么显然不合法,因为极限情况就是 (m=2n-2) 且黑白边各染成一棵树,再多一条边树就会变成基环树,也就会出现环了,因此必定会导致不合法。那么其余情况呢?我们还可以发现,如果存在原图的一个导出子图 (G(V,E)),满足 (|E|ge 2|V|-1),也会出现不合法的情况。那么如果不存在呢?可以证明,如果不存在一个非空导出子图 (G(V,E)),满足 (|E|ge 2|V|-1)​​,那么必然合法,证明我不会,不过据说是对的。因此考虑找出 (|E|-2|V|) 最大的导出子图,这个可以用最大权闭合子图的套路求解,将每条边权值赋为 (1),每个点权值赋为 (-2),那么选一条边必选与其相关联的两个点,这样最大权闭合子图子图的模型不就出来了?上个网络流(最小割)即可。还有一个注意点,就是如果仅仅只这么建图,对于所有图跑出来的结果都是 No,因为网络流跑出来的结果都是空图,因此考虑强制一个点必须被选,具体方法就是从源点向这个点连权值 (infty) 的边即可。

    时间复杂度 (Tn^2sqrt{n})

    6. CF724E Goods transportation

    模拟网络流。

    首先我们有一个非常显然的网络流:

    • 对于每个点,连边 ((S,i,p_i),(i,T,s_i))
    • 对于每个 (i<j) 的点对 ((i,j)),连边 ((i,j,c))

    然后跑最大流。

    但这样显然过不去,考虑模拟网络流。按照模拟网络流的套路我们肯定要将最大流转化为最小割,因此考虑 (dp)(dp_{i,j}) 表示考虑了前 (i) 个点,第 (i) 个点前面有 (j) 个点与 (S) 相连的边的最小代价。那么分情况套路,如果 (i) 保留与 (T) 相连的边,那么 (dp_{i,j}leftarrow dp_{i-1,j}+j·c+s_i),如果 (i) 保留与 (S) 相连的边,那么 (dp_{i,j}leftarrow dp_{i-1,j-1}+p_i),这样 DP 是平方的,已经足以通过此题。不过还有更优秀的做法,考虑贪心,设 (a_i=c(n-i)+s_i-p_i),那么我们对于每个点,初始全断开与 (T) 相连的边,然后贪心地将 (a_i) 从小到大排序,每次令答案加上 (a_i-c(i-1)),取最小时刻的答案作为最终答案即可,时间复杂度 (nlog n)

    const int MAXN=1e4;
    int n,c,p[MAXN+5],s[MAXN+5];ll a[MAXN+5];
    int main(){
    	scanf("%d%d",&n,&c);ll res=0;
    	for(int i=1;i<=n;i++) scanf("%d",&p[i]);
    	for(int i=1;i<=n;i++) scanf("%d",&s[i]);
    	for(int i=1;i<=n;i++) a[i]=s[i]-p[i]+1ll*c*(n-i);
    	for(int i=1;i<=n;i++) res+=p[i];ll mn=res;
    	sort(a+1,a+n+1);
    	for(int i=1;i<=n;i++) res+=a[i]-1ll*c*(i-1),chkmin(mn,res);
    	printf("%lld
    ",mn);
    	return 0;
    }
    
  • 相关阅读:
    IIS“服务没有及时响应启动或控制请求”错误解决
    CSS Overflow属性详解
    访问二维数组的实例ActionScript
    mailto语法
    IIS重新注册asp.net
    flash 动态文本 html
    C++继承中构造函数、析构函数调用顺序及虚析构函数
    根据指定两个日期计算出这些时间内有多少天是周末 php程序函数代码
    计算一段日期内的周末天数(星期六,星期日总和)(
    计算一段日期内的周末天数(星期六,星期日总和
  • 原文地址:https://www.cnblogs.com/ET2006/p/wll-simple-problems.html
Copyright © 2011-2022 走看看