题目传送门:https://vjudge.net/problem/UVA-1440

看上去很像DAG的最小路径覆盖QwQ?

反正我是写了一个上下界网络流,建模方法清晰易懂。

建立源$s$,向每个原图中的点连边,下界为$0$,上界为$\infty$,表示在每个点可以放置无限多的人。

建立汇$t$,每个原图中的点向汇连边,下界为$0$,上界为$\infty$,表示人可以在任意一个点停止滑雪。

对于原图中的每条弧$<u,v>$,连边$<u,v>$,下界为$1$,上界为$\infty$,表示这条路至少要被检查一遍。

然后跑一个有源汇上下界最小流就好啦OvO。

不会求上下界网络流的看这里:http://www.cnblogs.com/mlystdcall/p/6734852.html

输出方案?瞎搞QwQ。任选一个“需要放置人的点”开始dfs,在每个点的出边中任选一个“还需要被访问的”继续dfs,详见代码和注释。

这样输出方案为什么是对的?时间太久远辣我已经忘辣QwQ。

代码如下:

 #include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue> using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = ; namespace ISAP {
const int MAXV = MAXN;
const int MAXE = ( MAXV*MAXV/ + MAXV* )*; struct Edge {
int u, v, c, f;
Edge(){}
Edge( int u, int v, int c, int f ):
u(u),v(v),c(c),f(f){}
}edge[MAXE<<];
int n, m, s, t, ss, tt;
int head[MAXV], nxt[MAXE<<], eid[MAXE<<], eidx;
void init( int n2, int ss2, int tt2 ) { // 初始化,设置附加源和附加汇
n = n2; ss = ss2; tt = tt2;
m = eidx = ;
memset( head, -, sizeof(head) );
}
int adde( int u, int v, int c ) { // 添加一条只有上界的边
int rtn = m;
eid[eidx] = m; nxt[eidx] = head[u]; head[u] = eidx++;
edge[m++] = Edge(u,v,c,);
eid[eidx] = m; nxt[eidx] = head[v]; head[v] = eidx++;
edge[m++] = Edge(v,u,,);
return rtn;
}
int adde2( int u, int v, int b, int c ) { // 添加一条有上下界的边,返回边的下标
int rtn = adde(u,v,c-b);
adde(ss,v,b);
adde(u,tt,b);
return rtn;
}
// 以下ISAP板子
int prev[MAXV], dist[MAXV], num[MAXV], cur[MAXV], res[MAXV];
queue<int> bfsq;
void bfs() {
for( int i = ; i <= n; ++i ) dist[i] = n;
dist[t] = ; bfsq.push(t);
while( !bfsq.empty() ) {
int u = bfsq.front(); bfsq.pop();
for( int i = head[u]; ~i; i = nxt[i] ) {
Edge &e = edge[eid[i]];
if( dist[e.v] == n ) {
dist[e.v] = dist[u] + ;
bfsq.push(e.v);
}
}
}
}
void augment() {
int u = t, flow = res[t];
while( u != s ) {
int i = prev[u];
edge[i].f += flow;
edge[i^].f -= flow;
u = edge[i].u;
}
}
bool advance( int &u ) {
for( int i = cur[u]; ~i; i = nxt[i] ) {
Edge &e = edge[eid[i]];
if( e.c > e.f && dist[e.v] + == dist[u] ) {
prev[e.v] = cur[u] = i;
res[e.v] = min( res[u], e.c - e.f );
u = e.v;
return true;
}
}
return false;
}
bool retreat( int &u ) {
if( --num[dist[u]] == ) return false;
int newd = n;
for( int i = head[u]; ~i; i = nxt[i] ) {
Edge &e = edge[eid[i]];
if( e.c > e.f ) newd = min( newd, dist[e.v] + );
}
++num[ dist[u] = newd ];
cur[u] = head[u];
if( u != s ) u = edge[prev[u]].u;
return true;
}
int solve( int s2, int t2 ) { // 以s2为源,t2为汇跑最大流
s = s2; t = t2;
bfs();
for( int i = ; i <= n; ++i )
cur[i] = head[i], ++num[dist[i]];
int u = s, flow = ;
res[s] = INF;
while( dist[s] < n ) {
if( u == t ) {
augment();
flow += res[t];
u = s;
}
if( !advance(u) )
if( !retreat(u) )
break;
}
return flow;
}
} int n, s, t, ss, tt; // 点的个数,源,汇,附加源,附加汇 namespace Solve {
using ISAP::head;
using ISAP::nxt;
using ISAP::eid;
using ISAP::Edge;
using ISAP::edge;
bool first;
void dfs( int u ) { // dfs输出方案
// printf( "Debug: u = %d\n", u );
if( !first ) putchar(' ');
first = false;
printf( "%d", u );
for( int i = head[u]; ~i; i = nxt[i] ) {
Edge &e = edge[eid[i]];
if( e.v <= n && e.f > ) { // 任选一条边走下去
// printf( "going eid = %d, from %d to %d, flow_left = %d\n", eid[i], e.u, e.v, e.f );
--e.f;
dfs(e.v);
return;
}
}
}
void addbound() { // 把每条边流量加上下界,恢复成原图的样子,方便输出方案
using ISAP::m;
for( int i = ; i < m; ++i ) {
Edge &e = edge[eid[i]];
if( e.u <= n && e.v <= n && e.c > )
++e.f;
}
}
} namespace Debug { // 调试用QwQ
void print_flow() {
using ISAP::edge;
using ISAP::Edge;
using ISAP::eid;
using ISAP::m;
for( int i = ; i < m; ++i ) {
Edge &e = edge[eid[i]];
if( e.u <= n && e.v <= n && e.c > )
printf( "eid = %d, from %d to %d, flow = %d\n", eid[i], e.u, e.v, e.f );
}
}
void print_flow2() {
using ISAP::edge;
using ISAP::Edge;
using ISAP::eid;
using ISAP::m;
for( int i = ; i < m; ++i ) {
Edge &e = edge[eid[i]];
if( e.f > )
printf( "eid = %d, from %d to %d, flow = %d\n", eid[i], e.u, e.v, e.f );
}
}
} int main() {
while( scanf( "%d", &n ) == ) {
s = n+, t = n+, ss = n+, tt = n+;
ISAP::init(tt,ss,tt);
for( int i = ; i <= n; ++i ) {
int mi; scanf( "%d", &mi );
while( mi-- ) {
int v; scanf( "%d", &v );
ISAP::adde2(i,v,,INF);
}
ISAP::adde2(s,i,,INF);
ISAP::adde2(i,t,,INF);
}
int flow1 = ISAP::solve(ss,tt);
// printf( "flow1 = %d\n", flow1 );
// Debug::print_flow();
// Debug::print_flow2();
int tsedge = ISAP::adde2(t,s,,INF); // 存储弧<t,s>的信息,调试用QwQ
int ans = ISAP::solve(ss,tt);
// printf( "t_s flow = %d\n", ISAP::edge[tsedge].f );
// Debug::print_flow();
// Debug::print_flow2();
printf( "%d\n", ans );
Solve::addbound(); // 把每条图中的边流量加上下界,恢复成原图的样子,方便输出方案
while( ans ) {
using namespace Solve;
for( int i = head[s]; ~i; i = nxt[i] ) {
Edge &e = edge[eid[i]];
if( e.v <= n && e.f > ) { // 任选一个点dfs,输出方案
first = true;
--e.f;
--ans;
dfs(e.v);
putchar('\n');
}
}
}
}
return ;
}

【题解】Inspection UVa 1440 LA 4597 NEERC 2009的更多相关文章

  1. uva 1440 & uvalive 4597

    题目链接 题意: DAG的最小路径覆盖,一条边可以被重复覆盖多次,但是一次只能沿着DAG的方向覆盖一条链,问最少覆盖次数. 思路: 看了半天没有思路,所以去搜索了题解,然后发现是有源汇上下界的最小流, ...

  2. 题解 P1951 【收费站_NOI导刊2009提高(2)】

    查看原题请戳这里 核心思路 题目让求最大费用的最小值,很显然这道题可以二分,于是我们可以二分花费的最大值. check函数 那么,我们该怎么写check函数呢? 我们可以删去费用大于mid的点以及与其 ...

  3. 【题解】Casting Spells LA 4975 UVa 1470 双倍回文 SDOI 2011 BZOJ 2342 Manacher

    首先要吐槽LRJ,书上给的算法标签是“有难度,需要结合其他数据结构”,学完Manacher才发现几乎一裸题 题目的意思是问原串中有多少个wwRwwR这样的子串,其中wR表示w的反串 比较容易看出来,w ...

  4. UVa 1440:Inspection(带下界的最小流)***

    https://vjudge.net/problem/UVA-1440 题意:给出一个图,要求每条边都必须至少走一次,问最少需要一笔画多少次. 思路:看了好久才勉强看懂模板.良心推荐:学习地址. 看完 ...

  5. UVA - 1401 | LA 3942 - Remember the Word(dp+trie)

    https://vjudge.net/problem/UVA-1401 题意 给出S个不同的单词作为字典,还有一个长度最长为3e5的字符串.求有多少种方案可以把这个字符串分解为字典中的单词. 分析 首 ...

  6. 题解 【Uva】硬币问题

    [Uva]硬币问题 Description 有n种硬币,面值分别为v1, v2, ..., vn,每种都有无限多.给定非负整数S,可以选用多少个硬币,使得面值之和恰好为S?输出硬币数目的最小值和最大值 ...

  7. UVA 12097 LA 3635 Pie(二分法)

    Pie My birthday is coming up and traditionally I'm serving pie. Not just one pie, no, I have a numbe ...

  8. UVA题解三

    UVA题解三 UVA 127 题目描述:\(52\)张扑克牌排成一列,如果一张牌的花色或者数字与左边第一列的最上面的牌相同,则将这张牌移到左边第一列的最上面,如果一张牌的花色或者数字与左边第三列的最上 ...

  9. UVA题解二

    UVA题解二 UVA 110 题目描述:输出一个Pascal程序,该程序能读入不多于\(8\)个数,并输出从小到大排好序后的数.注意:该程序只能用读入语句,输出语句,if语句. solution 模仿 ...

随机推荐

  1. 电脑提示‘您需要来自Administration的权限才能对此文件夹进行更改’怎么删除文件

    电脑提示'您需要来自Administration的权限才能对此文件夹进行更改'怎么删除文件 应该怎么做 win7系统需要定期删除一些无用的文件,扩大内存空间,但是在删除文件的时候弹出提示"您 ...

  2. Sublime Text 3高效实用快捷键

    2017-11-27 16:18:48 Sublime Text 3 高效实用快捷键 Sublime Text 3 软件及注册码 官网下载链接在这里,有时候会很神奇的上不去,可能是因为被Q了,可能就是 ...

  3. js操作对象属性值为字符串

    今天在项目开发中遇到一个没遇到过的问题,这个问题是需要对比两个对象a和b,a是一个只有一个属性的对象,b是一个含有多个属性对象,如果b中包含和a一模一样的属性名和值,则把这个一样的属性和值从b中删除了 ...

  4. php序列化问题

    序列化是将变量转换为可保存或传输的字符串的过程:反序列化就是在适当的时候把这个字符串再转化成原来的变量使用.这两个过程结合起来,可以轻松地存储和传输数据,使程序更具维护性. 1. serialize和 ...

  5. scrum立会报告+燃尽图(第三周第一次)

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2284 项目地址:https://coding.net/u/wuyy694 ...

  6. Spring学习(六)—— Spring注解(二)

    核心原理 1.       用户发送请求给服务器.url:user.do 2.       服务器收到请求.发现Dispatchservlet可以处理.于是调用DispatchServlet. 3.  ...

  7. MAVEN项目标准目录结构 ;

    http://blog.csdn.net/lengyue_wy/article/details/6718637 版权声明:本文为博主原创文章,未经博主允许不得转载.    1.标准目录结构: src ...

  8. iOS 关于MVC和MVVM设计模式的那些事

    一.概述 在 iOS 开发中,MVC(Model View Controller)是构建iOS App的标准模式,是苹果推荐的一个用来组织代码的权威范式.Apple甚至是这么说的.在MVC下,所有的对 ...

  9. 【计算机基础】当你在浏览器中输入Google.com并且按下回车之后发生了什么?

    本文转载自:https://github.com/skyline75489/what-happens-when-zh_CN#id9 按下"g"键 接下来的内容介绍了物理键盘和系统中 ...

  10. 【转】史上最浅显易懂的Git教程!

    之前一直在找git的学习教程,网上搜到很多,但是大多数写的都非常简单或者混乱,你知道技术男的思维就是以为他抛一个专业术语出来,以为你都懂……或者简单写两句,插个图,他觉得他懂了,你也能懂,事实上初学者 ...