Portal -->bzoj2893

Descripiton

  给你一个\(n\)个点\(m\)条边的有向图,有一些点是起始点,有一些点是终止点,一次操作可以从一个起始点开始沿着有向图的边走到一个终止点(中途可以经过终止点),求需要至少多少次操作才能覆盖所有的点,无可行方案输出“no solution"

  数据范围:\(t<=10,n <= 1000, m <= 10000\),其中\(t\)为数据组数

Solution

​  首先肯定要缩点

​  完了之后重新建图我们就可以先直接判掉无解的情况了,如果说一个点(下面说的点都是缩完之后的点)的入度为\(0\)并且不能作为起点,或者说一个点出度为\(0\)并且不能作为终点那肯定不能走到这个点,所以肯定是无解的

​  否则一定存在一种方案覆盖所有的点

​  那现在就变成了一个求有向无环图的可相交最小点覆盖问题了

  然后。。不能天真的认为dfs或者大力dp可以直接搞定。。没那么简单qwq

  实际上这个有很多种做法,其中比较简洁的一种是有上下界的最小流

  具体建图的话就是,我们将一个原图中的一个点拆成两个,\(x\)和\(x'\)

​  然后\(x\rightarrow x'\)连一条容量下界为\(1\)上界为\(+\infty\)的边,表示每个点至少被经过一次

​  对于原图中的每条边\((u,v)\),我们建一条\(u'\rightarrow v\)的下界为\(0\)上界为\(+\infty\)的边,表示每条边最少可以不经过

  然后跑一遍上下界最小流就好啦,具体一点的话就是建附加源和汇,对于一条容量为\([l,r]\)从\(u\rightarrow v\)的边拆成三条边,附加源\(\rightarrow v\)流量为\(l\),附加汇\(\rightarrow u\)流量为\(l\),\(u\rightarrow v\)流量为\(r-l\),简单说一下理解的话就是前两条边是保证下界,最后一条边是在\([l,r]\)范围内随便流

​  这样建完图之后因为是要求有源汇的最小流,求解的话就是以附加源汇为起和终跑最大流,跑完了之后再加一条原来的汇\(\rightarrow\)源的\(+\infty\)的边,然后再在残留网络上跑一遍最大流就是答案了

​  具体的话。。我也不太会证明qwq可以去这篇博客膜拜

​   

  然后还有一种做法相对来说会麻烦一点点,就是有一个结论:如果我们按照如下方式建一个二分图:拆点,对于原图中\((u,v)\)的边,在二分图中连\(u\rightarrow v'\),那么原图点数\(n\)-二分图最大匹配数=原图的最小不可相交路径覆盖(其实就是Portal -->bzoj1143懒。。所以晚点再补博了qwq这里先贴一个题目链接)

​  如果我们再稍微改一下,先对原图用floyd做一次传递闭包,然后如果说两个点\(u,v\)满足\(u\)能够到达\(v\),那么在二分图中连一条\(u\rightarrow v'\)的边,这样用同样的方式计算就是原图的最小可相交路径覆盖了

​  然后这题的话我们也可以用这种方式来求解,这样就只用普通网络流来跑个匹配,但是之前还需要传递闭包(具体的话dtz说是先拓扑排序再直接大力dp,不过在这题里面时间是\(n^2\)级别的,但是因为\(n=1000\)所以问题不大%%%),大概是这样

  

​  第一种做法的代码大概长这个样子

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
const int N=1010,M=10010,inf=2147483647;
int stok[N],edok[N];
int n,m,t,cntst,cnted;
namespace F{/*{{{*/
struct xxx{
int y,nxt,op,r;
}a[M*10];
queue<int> q;
int lv[N*2],h[N*2];
int tot,S,T,SS,TT;//S和T是附加源汇,SS和TT是原来的源汇
void init(){
tot=-1;
memset(h,-1,sizeof(h));
}
void add1(int x,int y,int r){
//printf("%d %d %d\n",x,y,r);
a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot; a[tot].r=r;
a[++tot].y=x; a[tot].nxt=h[y]; h[y]=tot; a[tot].r=0;
}
void add(int x,int y,int l,int r){
add1(S,y,l);
add1(x,T,l);
add1(x,y,r-l);
}
bool bfs(){
while (!q.empty()) q.pop();
memset(lv,0,sizeof(lv));
q.push(S); lv[S]=1;
int u,v;
while (!q.empty()){
v=q.front(); q.pop();
for (int i=h[v];i!=-1;i=a[i].nxt){
u=a[i].y;
if (!a[i].r||lv[u]) continue;
lv[u]=lv[v]+1;
q.push(u);
if (u==T) return true;
}
}
return false;
}
int dfs(int v,int o){
if (!o||v==T) return o;
int u,ret=0,flow;
for (int i=h[v];i!=-1;i=a[i].nxt){
u=a[i].y;
if (!a[i].r||lv[u]!=lv[v]+1) continue;
flow=dfs(u,min(o,a[i].r));
if (flow){
o-=flow;
ret+=flow;
a[i].r-=flow;
a[i^1].r+=flow;
if (!o) break;
}
}
if (!ret) lv[v]=-1;
return ret;
}
int dinic(){
int ret=0;
while (bfs()) ret+=dfs(S,inf);
return ret;
}
}/*}}}*/
namespace G{/*{{{*/
struct xxx{
int y,nxt;
}a[M*2];
int h[N],dfn[N],low[N],st[N],id[N];
int Stok[N],Edok[N],ind[N],outd[N];
bool ins[N];
int tot,dfn_t,cnt,top;
void add(int x,int y){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;}
void init(){
memset(h,-1,sizeof(h));
tot=0;
memset(dfn,0,sizeof(dfn));
memset(ind,0,sizeof(ind));
memset(outd,0,sizeof(outd));
memset(ins,false,sizeof(ins));
memset(Stok,false,sizeof(Stok));
memset(Edok,false,sizeof(Edok));
top=0; cnt=0;
}
void tarjan(int x){
int u;
dfn[x]=low[x]=++dfn_t; st[++top]=x; ins[x]=true;
for (int i=h[x];i!=-1;i=a[i].nxt){
u=a[i].y;
if (!dfn[u]){
tarjan(u);
low[x]=min(low[x],low[u]);
}
else if (ins[u])
low[x]=min(low[x],dfn[u]);
}
if (low[x]==dfn[x]){
++cnt; u=st[top];
while (u!=x){
id[u]=cnt;
if (stok[u]) Stok[cnt]=true;
if (edok[u]) Edok[cnt]=true;
ins[u]=false;
u=st[--top];
}
id[x]=cnt;
if (stok[x]) Stok[cnt]=true;
if (edok[x]) Edok[cnt]=true;
ins[x]=false;
--top;
}
}
bool rebuild(){
int u;
dfn_t=0;
for (int i=1;i<=n;++i)
if (dfn[i]==0) tarjan(i);
F::SS=cnt*2+1; F::TT=F::SS+1;
F::S=F::SS+2; F::T=F::SS+3;
for (int i=1;i<=n;++i)
for (int j=h[i];j!=-1;j=a[j].nxt){
u=a[j].y;
if (id[i]!=id[u]){
++ind[id[u]],++outd[id[i]];
F::add(id[i]+cnt,id[u],0,inf);
}
}
for (int i=1;i<=cnt;++i){
F::add(i,i+cnt,1,inf);
if (!ind[i]){
if (!Stok[i]) return false;
F::add(F::SS,i,0,inf);
}
if (!outd[i]){
if (!Edok[i]) return false;
F::add(i+cnt,F::TT,0,inf);
}
}
return true;
}
}/*}}}*/
void solve(){
if (!G::rebuild()){printf("no solution\n");return;}
F::dinic();
F::add(F::TT,F::SS,0,inf);
int ans=F::dinic();
printf("%d\n",ans);
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int x,y;
scanf("%d",&t);
for (int o=1;o<=t;++o){
scanf("%d%d%d%d",&n,&m,&cntst,&cnted);
G::init();
memset(stok,false,sizeof(stok));
memset(edok,false,sizeof(edok));
for (int i=1;i<=cntst;++i)
scanf("%d",&x),stok[x]=true;
for (int i=1;i<=cnted;++i)
scanf("%d",&x),edok[x]=true;
for (int i=1;i<=m;++i){
scanf("%d%d",&x,&y);
if (x!=y) G::add(x,y);
}
F::init();
solve();
}
}

【bzoj2893】征服王的更多相关文章

  1. BZOJ2893: 征服王

    题解: 裸的上下界最小流是有问题的.因为在添加了附加源之后求出来的流,因为s,t以及其它点地位都是平等的.如果有一个流经过了s和t,那么总可以认为这个流是从s出发到t的满足题意的流. 既然可能存在s到 ...

  2. BZOJ2893:征服王(费用流)

    Description 虽然春希将信息传递给了雪菜,但是雪菜却好像完全不认得春希了.心急如焚的春希打开了第二世代机能,对雪菜的脑内芯片进行了直连-hack. 进入到雪菜内部的春希发现(这什么玩意..) ...

  3. 【BZOJ-2893】征服王 最大费用最大流(带下界最小流)

    2893: 征服王 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 156  Solved: 48[Submit][Status][Discuss] D ...

  4. SDOI2017 Round1

    SDOI2017 Round1 在回去的车上写的 cnblog的markdown貌似有bug,空行都没有了 Day -several [清明节] 没想到在省选之前还会有一次放假 放假前一天晚上走到校门 ...

  5. bzoj AC倒序

    Search GO 说明:输入题号直接进入相应题目,如需搜索含数字的题目,请在关键词前加单引号 Problem ID Title Source AC Submit Y 1000 A+B Problem ...

  6. 安晓辉大神的感悟:如果你发现了自己的学习模式,愿意学并且能坚持,我觉得没什么能阻挡你征服软件世界的脚步(对于开发人员来讲,最大的风险是:在职业规划上没有延续性地乱跳槽。时刻要牢记在心的:培养自己的稀缺性) good

    从技术支持中途转战软件开发,如今从事编程工作已十多有余,2014年CSDN博文大赛编程语言组冠军.CSDN Qt论坛的版主安晓辉老师从今天开始,坐镇CSDN社区问答栏目的 第十四期,届时会接受广大网友 ...

  7. 彻底征服 Spring AOP 之 理论篇

    基本知识 其实, 接触了这么久的 AOP, 我感觉, AOP 给人难以理解的一个关键点是它的概念比较多, 而且坑爹的是, 这些概念经过了中文翻译后, 变得面目全非, 相同的一个术语, 在不同的翻译下, ...

  8. BZOJ 4008 【HNOI2015】 亚瑟王

    题目链接:亚瑟王 这道题好神啊TAT--果然我的dp还是太弱了-- 一开始想了半天的直接dp求期望,结果最后WA的不知所云-- 最后去翻了题解,然后发现先算概率,再求期望--新姿势\(get\). 我 ...

  9. Bzoj4008 [HNOI2015]亚瑟王

    Time Limit: 20 Sec  Memory Limit: 512 MBSec  Special Judge Submit: 1009  Solved: 605[Submit][Status] ...

随机推荐

  1. appium -- 页面出现弹窗,关闭后,无法识别页面元素(转)

    原文:https://www.cnblogs.com/leavescy/p/9733001.html; 1. 问题:如图所示:在修改手势密码的过程中,点击了返回按钮后,弹出该弹窗:点击继续设置后,就发 ...

  2. JMeter:全面的乱码解决方案【转】

    本文是转自https://www.cnblogs.com/mawenqiangios/p/7918583.html 感谢分享者   中文乱码一直都是比较让人棘手的问题,我们在使用Jmeter的过程中, ...

  3. 机器学习与R语言——基本语法

    一.注释 1.选中要注释的内容,快捷键Ctrl+Shift+C(取消注释方法相同) 2.在需注释内容前输入# #需注释的内容 3.利用if语句,将判断条件设置为false则可跳过if语句中的内容,相当 ...

  4. NO.08--VUE之自定义组件添加原生事件

    前几篇给大家分享了我的业余的“薅羊毛”的经历,回归正题,讲回vue吧: 许多vue新手在工作开发中会遇到一个问题,直接使用 button 添加原生事件是没有问题的,但是使用自定义组件添加原生事件时,就 ...

  5. Qt creator 最常用的13个快捷键

    alt +enter // 自动创建类的定义 F1 // 查看帮助,文档 F2 // 快速到变量声明 Shift + F2 // 函数的声明和定义之间快速切换 F4 // 在 cpp 和 h 文件切换 ...

  6. 城市规模越大,工资、GDP、犯罪率越高:4.5星|《规模》

    规模 信息浓度非常高的一本书.篇幅也不小,纸书有568页,致谢与注释只占7%. 全书讲各种复杂的东西中存在的普遍规律:哺乳动物体重每增加一倍,心率降低25%:城市人口每增加一倍,加油站只增加85%:城 ...

  7. Prometheus+Grafana监控部署实践

    参考文档: Prometheus github:https://github.com/prometheus grafana github:https://github.com/grafana/graf ...

  8. CentOS7.x安装Docker1.11.1

    原文发表于cu:2016-05-30 本文属于重发,当前Docker已经分为EE与CE版本,CE版本是17.06.0-ce,最新的CE版本安装方式已略有不同:但可以指定安装版本,如1.11.1,1.1 ...

  9. 关于kv的jch分片存储

    确定节点同步一致 节点启动之后,先获取本地的addrbook里面的节点信息 根据获取的addrbook里面的节点信息进行校验(向addrbook里面的节点发送hash消息确认,如果都一样,则可以广播数 ...

  10. mac react-native从零开始android真机测试

    1. 安装android相关jdk,(https://blog.csdn.net/vvv_110/article/details/72897142) 2. 手机和mac使用usb连接, 手机开发者设置 ...