Codeforces 1383F - Special Edges(状态压缩+最大流)
首先暴力显然是不行的,如果你暴力最大流过了我请你吃糖
注意到本题的 \(k\) 很小,考虑以此为突破口解题。根据最大流等于最小割定理,点 \(1\) 到点 \(n\) 的最大流,等于边权和最小的边集 \(E\) 的边权和,满足割掉 \(E\) 中的边后 \(1\) 与 \(n\) 不连通(这里稍微多说几句,关于最大流最小割的“割”,最原始的定义是将点集 \(V\) 分成两个点集 \(V_1,V_2\),满足 \(V_1\cup V_2=V\),并且 \(S\in V_1,T\in V_2\),并且定义了割的权值 \(\sum\limits_{u\in V_1,v\in V_2}c(u,v)\),最上面的“割掉 \(E\) 的边后 \(1\) 与 \(n\) 不连通”有本质区别,上述结论只是它的一个推论)。我们不妨枚举 \(E\) 与特殊边集合的并集 \(S\),也就是说对于 \(S\) 中的特殊边我们强制要求它必须被割掉,对于不在 \(S\) 中的特殊边我们强制要求它不能被割掉。显然这样的 \(S\) 总共有 \(2^k\) 个,因此我们可以对每个 \(S\) 计算答案并更新 \(ans\)。
那么怎么计算集合 \(S\) 的答案呢?首先集合 \(S\) 中的边的权值是肯定要累加入答案中的,因此我们首先求出 \(\sum\limits_{e\in S}w_e\),这个显然可以通过类似于前缀和的东西以单组询问 \(2^k\) 的复杂度预处理出来。接下来考虑怎么计算不在 \(S\) 中的边的贡献,我们建一张新图,包含所有非特殊边和所有不在 \(S\) 中的特殊边,其中非特殊边的容量就是其本身的容量,特殊边的容量为 \(\infty\),因为它不能被割掉,当然由于 \(w\le 25\) 你也可以将其设为 \(25\)。至于 \(S\) 中的特殊边……既然它已经被鸽割掉了就不用管它了。我们只需在这张图上跑一遍最小割即最大流即可。
不过问题又来了,根据常识点数边数 \(10^4\) 级别的图跑最大流复杂度大约是 \(10^7\) 级别的,而我们对 \(2^k\) 个集合每个都跑一遍最大流,复杂度高达 \(10^{10}\),无法通过。不过注意到这 \(2^k\) 张图都是在原本非特殊边构成的图的基础上,添加 \(\le k\) 条容量为 \(25\) 的特殊边构成的,因此我们考虑先对非特殊边跑一遍最大流求出它的残余网络,然后对所有集合 \(S\) 在残余网络上加边跑出新增的流量。注意到这题边的容量很小,因此 Dinic 复杂度甚至不如最朴素的 FF 算法。具体来说,我们随便找一条 \(1\to n\) 的增广路径并更新流量,可以证明这样做的复杂度是 \(\mathcal O(wm)\),因此总复杂度就降到了 \(2^k·wm+q2^k\)。
这是蒟蒻第一次写 FF 哦,早安,Dinic 人
还有就是此题非常卡常,既卡 TLE 又卡 MLE,我大约交了十几发才通过,这里给出几个小卡常技巧:
- 由于此题边数 \(\le 2\times 10^4<2^{16}\),因此数组可以开成
short,这样空间常数可小一半。 - 在 FF 的过程中,如果发现已经 BFS 到了 \(n\) 就
break掉,及时停止,也算是一个小小的剪枝吧。 - 我是暴力开 \(2^{10}\) 个图的,我们记 \(G_S\) 为加入 \(S\) 中的边后跑完最大流后的残余网络,在计算 \(G_S\) 的最大流时,你不必以 \(G_0\) 为基础加入 \(|S|\) 条边,可以用
lowbit找到 \(S\) 中最小的元素并以 \(G_{S-\{x\}}\) 为基础,这样只用加入一条边,常数会小不少。 - 记得写读入优化,这题读入量有点大。
然鹅还是跑得很慢啊……最慢的点跑了 4.5s,几乎是卡时限过题,不保证下次提交依然可以通过。
namespace fastio{
#define FILE_SIZE 1<<23
char rbuf[FILE_SIZE],*p1=rbuf,*p2=rbuf,wbuf[FILE_SIZE],*p3=wbuf;
inline char getc(){return p1==p2&&(p2=(p1=rbuf)+fread(rbuf,1,FILE_SIZE,stdin),p1==p2)?-1:*p1++;}
inline void putc(char x){(*p3++=x);}
template<typename T> void read(T &x){
x=0;char c=getchar();T neg=0;
while(!isdigit(c)) neg|=!(c^'-'),c=getchar();
while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=getchar();
if(neg) x=(~x)+1;
}
template<typename T> void recursive_print(T x){if(!x) return;recursive_print(x/10);putc(x%10^48);}
template<typename T> void print(T x){if(!x) putc('0');if(x<0) putc('-'),x=~x+1;recursive_print(x);}
void print_final(){fwrite(wbuf,1,p3-wbuf,stdout);}
}
using namespace fastio;
void chkmin(int &x,int y){(y-x>>31)&&(x=y);}
const int MAXN=1e4;
const int MAXM=2e4;
const int MAXK=10;
const int MAXMSK=1<<10;
const int INF=0x3f3f3f3f;
int n,m,k,qu,sum[MAXMSK+5];
int su[MAXK+5],sv[MAXK+5],sw[MAXK+5];
struct graph{
short int hd[MAXN+5],to[MAXM+5],nxt[MAXM+5],cap[MAXM+5],ec=1;
void adde(int u,int v,int w){
to[++ec]=v;cap[ec]=w;nxt[ec]=hd[u];hd[u]=ec;
to[++ec]=u;cap[ec]=0;nxt[ec]=hd[v];hd[v]=ec;
} short int dep[MAXN+5],now[MAXN+5];
bool getdep(){
memset(dep,-1,sizeof(dep));dep[1]=0;
queue<int> q;q.push(1);now[1]=hd[1];
while(!q.empty()){
int x=q.front();q.pop();
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=cap[e];
if(z&&!~dep[y]){
dep[y]=dep[x]+1;
now[y]=hd[y];q.push(y);
}
}
} return ~dep[n];
}
int getflow(int x,int f){
if(x==n) return f;int ret=0;
for(short int &e=now[x];e;e=nxt[e]){
int y=to[e],z=cap[e];
if(dep[y]==dep[x]+1&&z){
int w=getflow(y,min(f-ret,z));
ret+=w;cap[e]-=w;cap[e^1]+=w;
if(ret==f) return ret;
}
} return ret;
}
int dinic(){
int ret=0;
while(getdep()) ret+=getflow(1,INF);
return ret;
}
int ff_bfs(){
memset(dep,-1,sizeof(dep));dep[1]=0;
queue<int> q;q.push(1);
while(!q.empty()){
int x=q.front();q.pop();
for(int e=hd[x];e;e=nxt[e]){
int y=to[e],z=cap[e];
if(z&&!~dep[y]){
dep[y]=dep[x]+1;now[y]=e;
q.push(y);if(~dep[n]) break;
}
} if(~dep[n]) break;
} if(!~dep[n]) return 0;
int mn=25;
for(int i=n;i^1;i=to[now[i]^1]) chkmin(mn,cap[now[i]]);
for(int i=n;i^1;i=to[now[i]^1]) cap[now[i]]-=mn,cap[now[i]^1]+=mn;
return mn;
}
int ff(){
int delta=0,ret=0;
while(delta=ff_bfs()) ret+=delta;
return ret;
}
} g[MAXMSK+5];
int flw[MAXMSK+5];
int main(){
read(n);read(m);read(k);read(qu);
for(int i=1;i<=k;i++) read(su[i]),read(sv[i]),read(sw[i]);
for(int i=k+1,u,v,w;i<=m;i++) read(u),read(v),read(w),g[0].adde(u,v,w);
flw[0]=g[0].dinic();
for(int i=1;i<(1<<k);i++){
int lwb=i&-i;g[i]=g[i^lwb];
int id=32-__builtin_clz(lwb);
g[i].adde(su[id],sv[id],25);
flw[i]=flw[i^lwb]+g[i].ff();
// printf("%d %d\n",i,flw[i]);
}
// if(n==9743&&qu==200000&&sv[1]==209) cout<<clock()<<endl;
while(qu--){
for(int i=1;i<=k;i++) read(sw[i]);
for(int i=1;i<(1<<k);i++){
int lwb=i&-i,id=32-__builtin_clz(lwb);
sum[i]=sum[i^lwb]+sw[id];
} int ans=INF;
for(int i=0;i<(1<<k);i++){
// printf("%d %d %d\n",i,sum[i],flw[((1<<k)-1)^i]);
chkmin(ans,sum[i]+flw[((1<<k)-1)^i]);
} print(ans);putc('\n');
} print_final();
return 0;
}
Codeforces 1383F - Special Edges(状态压缩+最大流)的更多相关文章
- Escape(状态压缩+最大流,好题)
Escape http://acm.hdu.edu.cn/showproblem.php?pid=3605 Time Limit: 4000/2000 MS (Java/Others) Memo ...
- HDU3605:Escape(状态压缩+最大流)
Escape Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Subm ...
- HDU3605(KB11-M 状态压缩+最大流)
Escape Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Subm ...
- Codeforces 417D Cunning Gena(状态压缩dp)
题目链接:Codeforces 417D Cunning Gena 题目大意:n个小伙伴.m道题目,每一个监视器b花费,给出n个小伙伴的佣金,所须要的监视器数,以及能够完毕的题目序号. 注意,这里仅仅 ...
- HDU 3605 Escape(状态压缩+最大流)
http://acm.hdu.edu.cn/showproblem.php?pid=3605 题意: 有n个人和m个星球,每个人可以去某些星球和不可以去某些星球,并且每个星球有最大居住人数,判断是否所 ...
- Codeforces 1017D The Wu(状态压缩+预处理)
题意: 给你n m q,表示在这一组数据中所有的01串长度均为n,然后给你一个含有m个元素的multiset,之后有q次询问.每次询问会给你一个01串t和一个给定常数k,让你输出串t和multiset ...
- Codeforces C. A Simple Task(状态压缩dp)
题目描述: A Simple Task time limit per test 2 seconds memory limit per test 256 megabytes input standar ...
- hdu3605(最大流+状态压缩)
传送门:Escape 题意:给出每个人适合住的星球信息和该星球能住多少人 ,第一行给出n m 代表有 n 个人 m 个星球,然后接下来n行每行m个数字 1代表适合第 i 个星球 0 代表不适合第 i ...
- [CodeForces 11D] A Simple Task - 状态压缩入门
状态压缩/Bitmask 在动态规划问题中,我们会遇到需要记录一个节点是否被占用/是否到达过的情况.而对于一个节点数有多个甚至十几个的问题,开一个巨型的[0/1]数组显然不现实.于是就引入了状态压缩, ...
随机推荐
- 更好的 java 重试框架 sisyphus 入门简介
What is Sisyphus sisyphus 综合了 spring-retry 和 gauva-retrying 的优势,使用起来也非常灵活. 为什么选择这个名字 我觉得重试做的事情和西西弗斯很 ...
- UltraSoft - Alpha - Scrum Meeting 5
Date: Apr q9th, 2020. Scrum 情况汇报 进度情况 组员 负责 昨日进度 后两日任务 CookieLau PM 统筹个人进度,协助推进进度 辅助前后端连接工作 刘zh 前端 完 ...
- [no code][scrum meeting] Alpha 10
项目 内容 会议时间 2020-04-16 会议主题 用户管理第一版交付 会议时长 15min 参会人员 PM+后端组成员 $( "#cnblogs_post_body" ).ca ...
- 修改git仓库的远程地址
在我们开发的过程中,代码一般是由 git 来管理的,但有些时候我们的 git 仓库的地址可能发生了变换,比如我们使用的 gitLab 地址发生了变化,那么这个时候如何来将原项目的 git 地址进行修改 ...
- git为单独的仓库设置提交的用户名
在我们平时的学习中可能有这么一种需求,在公司进行开发的时候,一般会参与多个项目的开发,而项目提交代码时,一般请求情况下提供的用户都是同一个,而我们为了方便可能会使用全局进行git 用户名的配置.但是空 ...
- 乘风破浪,遇见上一代操作系统Windows 10 - 抢鲜尝试安装新微软商店(Microsoft Store)
背景 在微软官方文章的<十一项关于微软商店新知>中提到: 新的微软商店现在可在Windows 11上找到,我们很高兴地分享,它将在未来几个月内提供给Windows 10客户!我们将很快分享 ...
- Linux资料 帮你理清思路
很多同学接触linux不多,对linux平台的开发更是一无所知. 而现在的趋势越来越表明,作为一个优秀的软件开发人员,或计算机it行业从业人员,="" 掌握linux是一种很重要的 ...
- Relocations in generic ELF (EM: 40)
最近在搞机器上的wifi热点,需要移植一大堆东西,如hostapd\wpa_suppliant.dhcp等,这些玩意又依赖其他的一大堆库的移植,比如libnl,openssl等,今天在移植编译libn ...
- C语言的“隐式函数声明”违背了 “前置声明” 原则
这个问题来源于小组交流群里的一个问题: 最终问题落脚在 : 一个函数在main中调用了,必须在main之前定义或者声明吗? 我在自己的Centos上做了实验,结果是函数不需要,但是结构体(变量也要)需 ...
- 线程私有数据TSD——一键多值技术,线程同步中的互斥锁和条件变量
一:线程私有数据: 线程是轻量级进程,进程在fork()之后,子进程不继承父进程的锁和警告,别的基本上都会继承,而vfork()与fork()不同的地方在于vfork()之后的进程会共享父进程的地址空 ...