【考试记录】4.8 Path (网络流 —— 劲题)
手抄代码 + 学习指针 + 冥思苦想一晚上终于——在一瞬间开窍了。果然题目都是这样:突破了一个点,一切都是柳暗花明。
题面描述:

样例:

这道题目,首先注意到给定的边的性质:这些边在平面上构成了一棵树,区间之间互不相交,只有包含与外离两种关系。如果不考虑颜色的限制,我们将原图的边权转化为网络流中的流量,那么原图中的最短路就转化为了新图中的最小割。那么在张网络流的图上,我们应当如何限制颜色的制约关系呢?
首先一个明显的思路:这张图是一个树形的结构,画在一个类似数轴的东西上面会很容易发现最下面的一条链上的点是无论如何都要经过的;而不存在于这条链上的点,则一定不会被访问到,其所代表的颜色也一定不会被我们所选择。对于这样的点,我们将它们从我们的图上删去。最小割:将图中的点分做S割与T割的两个部分。我们对于每一个颜色都做出一个辅助点,若这个点位于S割,代表这个颜色被选择;位于T割,代表不被选择。
我们将所有的边画成树后,从所有的大区间层层推进的向其所包含的小区间连边(类似线段树)。注意在这里我们先忽略那些链接相邻两点的区间不作处理。一个显然的性质:一个大区间所跳过的点,一定包含了所有它包含的小区间跳过的点。那么我们就从区间往它跳过的颜色的点连上INF的边(如果大区间&小区间共同跳过了一个颜色,这条边从小区间->颜色)。注意之前我们确定一定不会经过的颜色,从它向T点连INF的边,保证它一定处于T割。
这样我们可以发现:如果不选择这一个点,说明我们的割线一定在这个颜色的点的上方->我们选择了所有跳过这个颜色的区间。如果选择一个点,说明我们的割线在这个点的下方->我们没有选择任何一个跳过这个颜色的区间。这样,限制就得以满足了。最后,那些链接相邻两点的边:如果包含于大区间,则由这些区间其中最小的一个向T点连边权值的流量的边,否则就从S连向T,流量也为边权值。
感觉读懂了之后除了感叹还是感叹——我学过网络流吗?不存在的。【摊手】
#include <bits/stdc++.h>
using namespace std;
#define maxn 10000
#define INF 99999
#define pb push_back
#define vec vector
int n, m, cnp, cnt, s, t;
int Map[maxn][maxn], lev[maxn], nxt[maxn];
int ans, a[maxn], id[maxn];
bool tag[maxn], mark[maxn], flag[maxn];
vector <int> u, v, w, c;
queue <int> q; int read()
{
int x = , k = ;
char c;
c = getchar();
while(c < '' || c > '') { if(c == '-') k = -; c = getchar(); }
while(c >= '' && c <= '') x = x * + c - '', c = getchar();
return x * k;
} struct node
{
int u, v, w; bool flag;
bool operator <(node t)
{ return v - u < t.v - t.u; } // 区间长度短的放在前面
}E[maxn]; struct edge
{
int v, f;
edge *nxt, *rev;
}e[], *p = e, *head[maxn], *cur[maxn]; void add(int u, int v, int f1, int f2)
{
*p = (edge) { v, f1, head[u], p + }, head[u] = p ++;
*p = (edge) { u, f2, head[v], p - }, head[v] = p ++;
} bool bfs()
{
memset(lev, , sizeof(lev));
q.push(s); lev[s] = ;
while(!q.empty())
{
int u = q.front(); q.pop();
for(edge *i = head[u]; i; i = i -> nxt)
{
if(!lev[i -> v] && i -> f)
{
lev[i -> v] = lev[u] + ;
q.push(i -> v);
}
}
}
return lev[t];
} int dfs(int x, int nf)
{
int ff = ;
if(x == t) return nf;
for(edge *i = cur[x]; i; i = i -> nxt)
{
if(!nf) break;
if(i -> f && lev[i -> v] == lev[x] + )
{
int af = dfs(i -> v, min(nf, i -> f));
i -> f -= af, i -> rev -> f += af, cur[x] = i;
ff += af, nf -= af;
}
}
cur[x] = head[x];
return ff;
} int Work(vec <int> u, vec <int> v, vec <int> w, vec <int> c)
{
memset(Map, , sizeof(Map));
for(int i = ; i < (int) u.size(); i ++)
Map[u[i]][v[i]] = Map[v[i]][u[i]] = min(Map[u[i]][v[i]], w[i]);
flag[n] = ;
for(int i = n - ; i; i --)
for(int j = i + ; j <= n; j ++)
flag[i] |= flag[j] && Map[i][j] < << ;
for(int i = ; i <= n; i = nxt[i])
{
a[id[i] = ++ cnt] = i; nxt[i] = n + ;
for(int j = i + ; j <= n; j ++)
if(Map[i][j] < << && nxt[i] > n && flag[j])
{ nxt[i] = j; break; }
for(int j = ; j < i; j ++)
if(Map[i][j] < << && id[j] && id[j] != cnt - )
E[++ cnp] = (node) { id[j], cnt, Map[i][j], };
}
if(a[cnt] != n) return -;
E[++ cnp] = (node) { id[], id[n], , };
sort(E + , E + cnp);
s = cnp, t = cnp + ;
for(int i = ; i <= n - ; i ++)
if(!id[i]) add(cnp + c[i - ], t, << , << );
for(int i = ; i <= cnp; i ++)
{
for(int j = ; j < i; j ++)
if(!E[j].flag && E[i].u <= E[j].u && E[i].v >= E[j].v)
E[j].flag = , add(i, j, E[j].w, << );
for(int j = E[i].u + ; j < E[i].v; j ++)
if(!tag[j]) tag[j] = , add(i, cnp + c[a[j] - ], << , << );
for(int j = E[i].u; j < E[i].v; j ++)
if(!mark[j]) mark[j] = , add(i, t, Map[a[j]][a[j + ]], );
}
for(int i = ; i <= t; i ++) cur[i] = head[i];
while(bfs()) if((ans += dfs(s, << )) >= INF) return -;
return ans;
} int main()
{
n = read(), m = read();
for(int i = ; i <= n - ; i ++)
{
int x = read();
c.pb(x);
}
for(int i = ; i <= m; i ++)
{
int x = read(), y = read(), z = read();
u.pb(x), v.pb(y), w.pb(z);
}
printf("%d\n", Work(u, v, w, c));
return ;
}
【考试记录】4.8 Path (网络流 —— 劲题)的更多相关文章
- 网络流n题 题解
学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...
- 【网络流24题】最长k可重区间集(费用流)
[网络流24题]最长k可重区间集(费用流) 题面 Cogs Loj 洛谷 题解 首先注意一下 这道题目里面 在Cogs上直接做就行了 洛谷和Loj上需要判断数据合法,如果\(l>r\)就要交换\ ...
- LibreOJ #6014. 「网络流 24 题」最长 k 可重区间集
#6014. 「网络流 24 题」最长 k 可重区间集 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 ...
- Libre 6013 「网络流 24 题」负载平衡 (网络流,最小费用最大流)
Libre 6013 「网络流 24 题」负载平衡 (网络流,最小费用最大流) Description G 公司有n 个沿铁路运输线环形排列的仓库,每个仓库存储的货物数量不等.如何用最少搬运量可以使n ...
- Libre 6012 「网络流 24 题」分配问题 (网络流,费用流)
Libre 6012 「网络流 24 题」分配问题 (网络流,费用流) Description 有n件工作要分配给n个人做.第i个人做第j件工作产生的效益为\(c_{ij}\).试设计一个将n件工作分 ...
- Libre 6011 「网络流 24 题」运输问题 (网络流,最小费用最大流)
Libre 6011 「网络流 24 题」运输问题 (网络流,最小费用最大流) Description W 公司有m个仓库和n个零售商店.第i个仓库有\(a_i\)个单位的货物:第j个零售商店需要\( ...
- LibreOJ #6013. 「网络流 24 题」负载平衡 最小费用最大流 供应平衡问题
#6013. 「网络流 24 题」负载平衡 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
- LIbreOJ #6011. 「网络流 24 题」运输问题 最小费用最大流
#6011. 「网络流 24 题」运输问题 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
- LibreOJ #6008. 「网络流 24 题」餐巾计划 最小费用最大流 建图
#6008. 「网络流 24 题」餐巾计划 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:文本比较 上传者: 匿名 提交提交记录统计讨论测试数据 题目描述 ...
随机推荐
- android 按钮动态点击
关键代码: 1.创建一个btn_selector.xml的文件 <?xml version="1.0" encoding="utf-8"?>< ...
- Yaf学习(二)----Yaf初体验
1.hello world 1.1 用yaf输出hello world 1.首先配置host,nginx 2.host不用多说,指向虚拟机IP即可 1.2 重点说一下nginx (只说server块) ...
- YII2.0 获取当前访问地址/IP信息
假设我们当前页面的访问地址是:http://localhost/CMS/public/index.php?r=news&id=1 一. 1.获取当前域名:echo Yii::app()-> ...
- doT.js使用介绍
doT.js特点是快,小,无依赖其他插件,压缩版仅有4K大小. doT.js详细使用介绍 使用方法: 1 2 3 4 5 6 7 {{ }} 模板 开始标记 结束标记 {{= }} 赋值 {{~ ...
- C中 snprintf()函数的作用
函数原型:int snprintf(char* dest_str,size_t size,const char* format,...); 函数功能:先将可变参数 “…” 按照format的格式格式化 ...
- List集合中的对象比较,取出不同对象
今天在做金碟系统与我们系统的对接的时候需要做一个客户同步 在同步时,需要比较对象,对查询出的数据库的数据进行比较 for(int i=0;i<list2.size();i++){ if(! li ...
- R语言学习笔记(十五):获取文件和目录信息
file.info() 参数是表示文件名称的字符串向量,函数会给出每个文件的大小.创建时间.是否为目录等信息. > file.info("z.txt") size isdir ...
- HDU 5530:Pipes Selection
题意: 给定长度为\(L\),元素总和为\(S\)的非负整数序列\(A\),对于每一个\(1 \leq i \leq S\),求出:所有满足\(\sum_{j=l}^rA_j=i\)的二元组\((l, ...
- 查看sql 作业明细及运行记录
--查看作业明细及状态 select j.name 'Job名', j.description '描述', j.ENABLED job_enabled, cast(js.last_run_date a ...
- app:showAsAction 和android:showAsAction
app:showAsAction 它有三个可选项1.always:总是显示在界面上2.never:不显示在界面上,只让出现在右边的三个点中3.ifRoom:如果有位置才显示,不然就出现在右边的三个点中 ...