【FJWC 2019】min
【FJWC 2019】min
题目描述
给你一张 \(n\) 个点 \(m\) 条边的无向图,走过每条边都需要花费 \(1\) 秒。
给你一个整数 \(k\) ,请你选择至多 \(k\) 个点,令经过这些点也需要花费 \(1\) 秒,使得从点 \(0\) 走到点 \(n-1\) 的最短时间最大。输出这个最大值。
注意,不能选择点 \(0\) 或点 \(n-1\) 。
输入格式
第一行三个正整数 \(n,m,k\) ,意义见题面描述。
接下来 \(m\) 行,每行两个数 \(x,y\) ,表示 \(x\) 和 \(y\) 之间存在一条边,保证 \(0 \le x,y < n\) ,不存在重边和自环,且点 \(0\) 和点 \(n-1\) 连通。
样例输入
3 2 1
0 1
1 2
样例输出
3
\(2 \le n \le 100,1 \le m \le n \times (n-1)/2,0 \le k \le n\)
感觉对网络流相关知识太不熟练了,这种题都要写自闭。
题解二分有点神仙。
我的做法复杂度就不那么优秀了。首先找到最短路,然后我们要求出选最少的点使得\(0\)到\(n-1\)最短路\(+1\)。我们很容易发现就是要选出最少的点割断使得\(0\)和\(n-1\)不连通。
网络流啊!
每个点拆成两个,流量为一,其他在最短路上的边也要连上,流量\(\infty\)。
我们每次做完网络流过后随便求出一个最小割集,这些点就是我们选的点。然后我们重新跑最短路,重新建图。那些选了的点之间流量\(\infty\),因为这些点不能再割了。
我们重复做,直到所有点选完或者\(k\)个点用完为止。
找出仍以一组最小割只需要从源点\(S\)出发,走富余边\(dfs\)一遍,得到点集\(\{S\}\)。如果一条满流边一个点\(\in\{S\}\),另一个不属于,那么这就是我们要选的点。
然而我智障地写了\(tarjan\)还有退流操作。。
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 205
using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}
int n,m,k;
struct road {
int to,next;
}s[N*N<<2];
int h[N],cnt;
void add(int i,int j) {s[++cnt]=(road) {j,h[i]};h[i]=cnt;}
int dis[N];
bool del[N];
struct node {
int v,d;
node() {v=d=0;}
node(int a,int b) {v=a,d=b;}
bool operator <(const node &a)const {
return d>a.d;
}
};
priority_queue<node>Q;
void dij() {
static bool in[N];
memset(dis,0x3f,sizeof(dis));
memset(in,0,sizeof(in));
dis[1]=0;
Q.push(node(1,0));
while(!Q.empty()) {
int v=Q.top().v;
Q.pop();
if(in[v]) continue ;
in[v]=1;
for(int i=h[v];i;i=s[i].next) {
int to=s[i].to;
if(in[to]) continue ;
if(dis[to]>dis[v]+1+del[to]) {
dis[to]=dis[v]+1+del[to];
Q.push(node(to,dis[to]));
}
}
}
}
int ans;
namespace dinic {
struct road {int to,next,f;}s[N*N<<2];
int h[N<<1],cnt=1;
int id[N];
void add(int i,int j,int f) {
s[++cnt]=(road) {j,h[i],f};h[i]=cnt;
s[++cnt]=(road) {i,h[j],0};h[j]=cnt;
}
int S,T;
int dis[N];
queue<int>q;
bool bfs(int S,int T) {
memset(dis,0x3f,sizeof(dis));
q.push(S);
dis[S]=0;
while(!q.empty()) {
int v=q.front();q.pop();
for(int i=h[v];i;i=s[i].next) {
int to=s[i].to;
if(s[i].f&&dis[to]>dis[v]+1) {
dis[to]=dis[v]+1;
q.push(to);
}
}
}
return dis[T]<1e9;
}
int dfs(int v,int maxf) {
if(v==T) return maxf;
int ret=0;
for(int i=h[v];i;i=s[i].next) {
int to=s[i].to;
if(s[i].f&&dis[to]==dis[v]+1) {
int dlt=dfs(to,min(maxf,s[i].f));
ret+=dlt;
s[i].f-=dlt;
s[i^1].f+=dlt;
maxf-=dlt;
if(!maxf) return ret;
}
}
return ret;
}
int dinic() {
int ans=0;
while(bfs(S,T)) {
while(1) {
int tem=dfs(S,1e9);
if(!tem) break ;
ans+=tem;
if(ans>=1e9) return ans;
}
}
return ans;
}
int dfn[N],low[N],tot;
int st[N],bel[N],scc;
bool ins[N];
void tarjan(int v) {
low[v]=dfn[v]=++tot;
ins[v]=1;
st[++st[0]]=v;
for(int i=h[v];i;i=s[i].next) {
int to=s[i].to;
if(!s[i].f) continue ;
if(!dfn[to]) {
tarjan(to);
low[v]=min(low[v],low[to]);
} else if(ins[to]) low[v]=min(low[v],dfn[to]);
}
if(dfn[v]==low[v]) {
scc++;
while(1) {
int j=st[st[0]--];
bel[j]=scc;
ins[j]=0;
if(j==v) break;
}
}
}
void Init() {
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(ins,0,sizeof(ins));
memset(bel,0,sizeof(bel));
tot=scc=0;
}
void Tarjan() {
Init();
for(int i=1;i<2*n;i++)
if(!dfn[i]&&i!=n+1) tarjan(i);
}
vector<int>tem;
bool dfs(int v) {
if(v==T) return 1;
for(int i=h[v];i;i=s[i].next) {
int to=s[i].to;
if(s[i].f&&dfs(to)) return 1;
}
return 0;
}
void Cut() {
Tarjan();
tem.clear();
for(int i=2;i<n;i++) {
if(s[id[i]].f) continue ;
if(bel[i]!=bel[i+n]) {
S=i,T=1;
dinic();
S=n,T=i+n;
dinic();
tem.push_back(i);
del[i]=1;
s[id[i]].f=s[id[i]^1].f=0;
S=1,T=n;
dinic();
Tarjan();
}
}
}
void build() {
cnt=1;
memset(h,0,sizeof(h));
for(int i=2;i<n;i++) {
if(del[i]) add(i,i+n,1e9);
else add(i,i+n,1);
}
for(int v=1;v<n;v++) {
for(int i=::h[v];i;i=::s[i].next) {
int to=::s[i].to;
if(::dis[to]==::dis[v]+1+del[to]) {
if(v>1) add(v+n,to,1e9);
else add(v,to,1e9);
}
}
}
}
void solve() {
int res=k;
int tim=0;
while(1) {
S=1,T=n;
int now=dinic();
if(res<now) return ;
res-=now;
ans++;
Cut();
dij();
build();
}
return ;
}
}
int main() {
n=Get(),m=Get(),k=Get();
int a,b;
for(int i=1;i<=m;i++) {
a=Get()+1,b=Get()+1;
add(a,b),add(b,a);
}
dij();
for(int i=2;i<n;i++) {
dinic::id[i]=dinic::cnt+1;
dinic::add(i,i+n,1);
}
for(int v=1;v<n;v++) {
for(int i=h[v];i;i=s[i].next) {
int to=s[i].to;
if(dis[to]==dis[v]+1) {
if(v>1) dinic::add(v+n,to,1e9);
else dinic::add(v,to,1e9);
}
}
}
ans=dis[n];
dinic::solve();
cout<<ans<<"\n";
return 0;
}
【FJWC 2019】min的更多相关文章
- 【FJWC 2019】 森林
[FJWC 2019] 森林 样例输入 0 5 1 0 0 2 样例输出 1 2 3 3 我们发现,答案就是直径加上直径上某个点出发,不经过其他直径上的点的最长链.这里的直径可以是任意一条直径. 首先 ...
- 【等价转换】—— min/max 的转换与互相转换
0. min 与 max 的转换 {max(X,Y)=X+Y−min(X,Y)min(X,Y)=X+Y−max(X,Y)min(X,Y)+max(X,Y)=X+Y" role="p ...
- 【ZJOI 2019】麻将(dp of dp)
这是我第一次写$dp \; of \; dp$,大致思路参考了xyx的做法,可能有些地方不太一样,但也许会详细一点. 考虑给你一副牌,如何判断这副牌是否是胡的. 容易发现相同的顺子不会选三个以上,于是 ...
- 【GZOI 2019】特技飞行
Problem Description 公元 \(9012\) 年,Z 市的航空基地计划举行一场特技飞行表演.表演的场地可以看作一个二维平面直角坐标系,其中横坐标代表着水平位置,纵坐标代表着飞行高度. ...
- 【HNOI 2019】JOJO
Problem Description JOJO 的奇幻冒险是一部非常火的漫画.漫画中的男主角经常喜欢连续喊很多的「欧拉」或者「木大」. 为了防止字太多挡住漫画内容,现在打算在新的漫画中用 \(x\) ...
- 【CSP-SJX 2019】T4 散步
Description 传送门 Solution 算法1 32pts 枚举每个时刻,并枚举所有发生的时间,暴力进行更新.发现最多只需要枚举到第 \(L\)个时刻,因为是一个环,所以最多到第L个时刻,所 ...
- 【CSP-S 2019】D2T2 划分
Description 传送门 Solution 算法1 12pts 指数算法随便乱搞. 算法2 36pts \(O(n^3)\)dp. 设\(f_{i,j}\)表示以位置\(j\)结尾,上一个决策点 ...
- 【JOISC2019|2019】【20190622】cake3
题目 \(N\) 个物品中选\(M\)个,排列成一个环:\(k_1,\cdots,k_M\)价值为: \[ \sum_{j=1}^{N}{V_i} - \sum_{j=1}^{M}|C_{k_j}- ...
- 【CSP-S 2019】【洛谷P5665】划分【单调队列dp】
前言 \(csp\)时发现自己做过类似这道题的题目 : P4954 [USACO09Open] Tower of Hay 干草塔 然后回忆了差不多\(15min\)才想出来... 然后就敲了\(88p ...
随机推荐
- DirBuste 使用
https://sourceforge.net/projects/dirbuster/ 官网下载 记得安装java 运行环境 这是扫描 443 端口的数据 也可以自己写字典规则 在选择模糊查询时 下面 ...
- NGUI 做局部2d卷轴
网上找到的都是做整个背景的卷轴动画,通常是改变纹理位置或者背景图片的x坐标 没有提到在UI界面里某个部分做卷轴动画,找了很久,才发现NGUI的Panel里的Clipping属性可以裁剪Panel的大小 ...
- 模块热替换 HMR
devserver:{hot:true},既及时更新代码,样式(需配合loader)变化,自动重编译,只适用于开发环境. 入口文件中,添加监视: + if (module.hot) {+ module ...
- Python中的特殊属性与方法
模块的特殊属性 __doc__ 模块的说明文档 __all__ 指明模块希望被使用的属性.类和方法 __file__ 模块所在路径 类的特殊属性 __slots__ 限制类的实例允许添加的属性,是一个 ...
- blfs(systemd版本)学习笔记-编译安装配置dhcpcd
我的邮箱地址:zytrenren@163.com欢迎大家交流学习纠错! dhcpcd项目地址:http://www.linuxfromscratch.org/blfs/view/stable-syst ...
- iphone屏幕镜像 屏幕镜像怎么用
iPhone手机投屏到电脑设备上,需要使用到AirPlay镜像功能,但是有些苹果新用户朋友一定还不知道iphone屏幕镜像怎么用吧?你要着急下面为你提供解决方法. 使用工具:iphone.电脑 操作方 ...
- SD: 关于价格过程的确定
在SD模块中,定价过程是一个非常重要的功能,在单据中使用哪个定价过程取决于三个因素 1)销售区域(sale Area) 该数据来自Sold-to Party的客户维护的销售数据. 2)客户主数据的定价 ...
- 【Wyn Enterprise BI知识库】 认识多维数据建模与分析 ZT
与业务系统类似,商业智能的基础是数据.但是,因为关注的重点不同,业务系统的数据使用方式和商业智能系统有较大差别.本文主要介绍的就是如何理解商业智能所需的多维数据模型和多维数据分析. 数据立方体 多维数 ...
- 浅谈Kotlin(一):简介及Android Studio中配置
浅谈Kotlin(一):简介及Android Studio中配置 浅谈Kotlin(二):基本类型.基本语法.代码风格 浅谈Kotlin(三):类 浅谈Kotlin(四):控制流 前言: 今日新闻:谷 ...
- 六. Redis发布订阅机制
发布订阅(pub/sub)是一种消息通信模式,主要是解除消息发布者和消息订阅者之间通信的耦合. Redis作为一个pub/sub的服务器,在订阅者和发布者之间起到了一个消息路由的功能.订阅者可以通过s ...