【BZOJ2324】[ZJOI2011]营救皮卡丘(网络流,费用流)

题面

BZOJ

洛谷

题解

如果考虑每个人走的路径,就会很麻烦。

转过来考虑每个人破坏的点集,这样子每个人可以得到一个上升的序列。

预处理\(dis[u][v]\)表示\(u\rightarrow v\)在不经过标号大于\(max\{u,v\}\)的点的情况下的最短路。

这个可以\(Floyd\)预处理。

不妨把\(0\)号点加入到每个人的序列开头,这样子一个假设一个人的序列是\(P\),那么他经过的所有边的和就是\(\sum_{i=2}^{|P|}dis[P_{i-1}][P_i]\)。

这样子就可以构建一个\(DAG\),然后要找出不超过\(k\)条路径来覆盖,对于两个点\(i,j,i<j\),从\(i\)到\(j\)的费用为\(dis[i][j]\)。

为了强制每个点都被访问过,把点拆成两个,因为是路径覆盖,所以每个点入度出度一进一出。

把每个点拆成入点和出点,出点作为\(i\),向其他点\(j\)的出点连边。

然后入点向\(T\)连边,表示必须有一个前驱,然后\(S\)向出点连边,表示必须有个后继。

然后\(S\)向\(0\)的出点连边,容量为\(K\),表示\(K\)条路径。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MAX 155
const int inf=150100;
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
namespace MCMF
{
const int MAXM=1000000,MAXN=1000;
struct Line{int v,next,w,fy;}e[MAXM];
int h[MAXN],cnt=2;
inline void Add(int u,int v,int w,int fy)
{
e[cnt]=(Line){v,h[u],w,fy};h[u]=cnt++;
e[cnt]=(Line){u,h[v],0,-fy};h[v]=cnt++;
}
int dis[MAXN],pe[MAXN],pv[MAXN],Cost,Flow;
bool vis[MAXN];queue<int> Que;
int S=MAXN-2,T=MAXN-1;
bool SPFA()
{
memset(dis,63,sizeof(dis));dis[S]=0;
Que.push(S);vis[S]=true;
while(!Que.empty())
{
int u=Que.front();Que.pop();
for(int i=h[u];i;i=e[i].next)
{
int v=e[i].v;if(!e[i].w)continue;
if(dis[u]+e[i].fy<dis[v])
{
dis[v]=dis[u]+e[i].fy;pe[v]=i,pv[v]=u;
if(!vis[v])vis[v]=true,Que.push(v);
}
}
vis[u]=false;
}
if(dis[T]>=1e9)return false;
int flow=1e9;
for(int i=T;i!=S;i=pv[i])flow=min(flow,e[pe[i]].w);
for(int i=T;i!=S;i=pv[i])e[pe[i]].w-=flow,e[pe[i]^1].w+=flow;
Flow+=flow;Cost+=dis[T]*flow;
return true;
}
}
using namespace MCMF;
int n,m,K,g[MAX][MAX];
int main()
{
n=read();m=read();K=read();
memset(g,63,sizeof(g));for(int i=0;i<=n;++i)g[i][i]=0;
for(int i=1,u,v;i<=m;++i)u=read(),v=read(),g[u][v]=g[v][u]=min(g[u][v],read());
for(int k=0;k<=n;++k)
for(int i=0;i<=n;++i)
for(int j=0;j<=n;++j)
if(k<=i||k<=j)g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
Add(S,0+n+1,K,0);
for(int i=1;i<=n;++i)Add(S,i+n+1,1,0),Add(i,T,1,0);
for(int i=0;i<=n;++i)
for(int j=i+1;j<=n;++j)
Add(i+n+1,j,1,g[i][j]);
while(SPFA());printf("%d\n",Cost);
return 0;
}

【BZOJ2324】[ZJOI2011]营救皮卡丘(网络流,费用流)的更多相关文章

  1. BZOJ2324 [ZJOI2011]营救皮卡丘 【费用流】

    题目 皮卡丘被火箭队用邪恶的计谋抢走了!这三个坏家伙还给小智留下了赤果果的挑衅!为了皮卡丘,也为了正义,小智和他的朋友们义不容辞的踏上了营救皮卡丘的道路. 火箭队一共有N个据点,据点之间存在M条双向道 ...

  2. BZOJ 2324: [ZJOI2011]营救皮卡丘( floyd + 费用流 )

    昨晚写的题...补发一下题解... 把1~N每个点拆成xi, yi 2个. 预处理i->j经过编号不超过max(i,j)的最短路(floyd) S->0(K, 0), S->xi(1 ...

  3. 【洛谷P4542】 [ZJOI2011]营救皮卡丘(费用流)

    洛谷 题意: 给出\(n\)个点,\(m\)条边,现在有\(k,k\leq 10\)个人从\(0\)号点出发前往\(n\)点. 规定若某个人想要到达\(x\)点,则\(1\)~\(x-1\)号点都有人 ...

  4. 【洛谷 P4542】 [ZJOI2011]营救皮卡丘(费用流)

    题目链接 用最多经过\(k\)条经过\(0\)的路径覆盖所有点. 定义\(ds[i][j]\)表示从\(i\)到\(j\)不经过大于\(max(i,j)\)的点的最短路,显然可以用弗洛伊德求. 然后每 ...

  5. bzoj2324 [ZJOI2011]营救皮卡丘 费用流

    [ZJOI2011]营救皮卡丘 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2653  Solved: 1101[Submit][Status][D ...

  6. BZOJ2324: [ZJOI2011]营救皮卡丘

    2324: [ZJOI2011]营救皮卡丘 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 1359  Solved: 522[Submit][Stat ...

  7. BZOJ2324 ZJOI2011营救皮卡丘(floyd+上下界费用流)

    虽然不一定每次都是由编号小的点向编号大的走,但一个人摧毁的顺序一定是从编号小的到编号大的.那么在摧毁据点x的过程中,其只能经过编号小于x的点.并且这样一定合法,因为可以控制其他人先去摧毁所经过的点.那 ...

  8. P4542-[ZJOI2011]营救皮卡丘【费用流,Floyd】

    正题 题目链接:https://www.luogu.com.cn/problem/P4542 题目大意 给出\(n+1\)个点\(m\)条边的无向图,\(k\)个人开始在\(0\)号点,一个人进入\( ...

  9. 【BZOJ2324】[ZJOI2011]营救皮卡丘 有上下界费用流

    [BZOJ2324][ZJOI2011]营救皮卡丘 Description 皮卡丘被火箭队用邪恶的计谋抢走了!这三个坏家伙还给小智留下了赤果果的挑衅!为了皮卡丘,也为了正义,小智和他的朋友们义不容辞的 ...

随机推荐

  1. 利用php查看某个服务的进程数

    查看进程就是使用ps命令而已,只不顾ps的参数太多了. 使用php查询的话,必须要开启几个函数(可以执行外部程序的函数),参考官网:http://php.net/manual/zh/book.exec ...

  2. PAT L2-013 红色警报

    https://pintia.cn/problem-sets/994805046380707840/problems/994805063963230208 战争中保持各个城市间的连通性非常重要.本题要 ...

  3. 面试题(校招java)

    1:linux线程和进程的区别? 进程是程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集.从内核的观点看,进程的目的就是担当分配系统资源(CPU时间.内存等)的基本单位. 线程是进程 ...

  4. [转帖]system()、exec()、fork()三个与进程有关的函数的比较

    system().exec().fork()三个与进程有关的函数的比较 https://www.cnblogs.com/qingergege/p/6601807.html 启动新进程(system函数 ...

  5. Linux上的一些基本常用命令

    上传下载文件:// 首先安装lrzsz # yum -y install lrzsz // 上传文件,执行命令rz,会跳出文件选择窗口,选择好文件,点击确认即可.# rz // 下载文件,执行命令sz ...

  6. mysql [assword expired

    mysql 5.6 在使用Navicat在其他机器上进行远程登录数据库时 会出现 password expired ,需要重新设置一下密码. SET PASSWORD FOR 'root'@'%' = ...

  7. switch-case和if-else可互换时

    当switch-case和if-else可互换时,应当优先采用switch-case.因为switch-case的效率更高(详情下回分解).

  8. Numpy中array数据操作

    1.创建: import numpy as np arr=np.array([1,2,3]) print(arr,arr.ndim) list=[1,2,3] arr=np.array(list) 2 ...

  9. 在linux系统中实现各项监控的关键技术(1)--cpu使用率的计算

    转载自 Linux中通过/proc/stat等文件计算Cpu使用率 http://www.blogjava.net/fjzag/articles/317773.html proc文件系统 /proc文 ...

  10. python学习笔记(10)--组合数据类型(集合类型)

    集合类型 集合是多个元素的无序组合,每个元素唯一,不存在相同类型,每个元素是不可变类型.用{}表示,元素间用逗号分隔.建立结合类型用{},或set函数,如果是空集合必须用set. >>&g ...