[JZOJ3348] 【NOI2013模拟】秘密任务
题目
题目大意
给你一个无向图,你要割掉一些边使得\(1\)到\(n\)的所有最短路径被阻截。
割掉一个边\((u,v)\)的代价为\(a_u\)或\(a_v\)(记为两种不同的方案)。
问最小代价及其唯一性。
思考历程
首先要将最短路图给建出来。
然后我就莫名其妙地想到了支配树,还在这个方向上思考了一阵子……
想不到怎么做……
然后我又想到之前某道题,将最大反链长度转化为最小链覆盖,然后用二分图匹配来实现。
我模仿着打了个KM算法,然后发现果然错了……
看来是不能直接生搬硬套的……
然后蓦然发现:这道题不就是个最小割吗!
于是就开始狂打……
最终的问题就是:如何判断唯一性……
匆匆忙忙地打了个错误的方法,交了上去。
正解
这题当然是最小割啦……
由于每条边选\(a_u\)和\(a_v\)算作两种方案,所以每条边要拆成两条来搞。
建图当然显然了。
至于判断是否有唯一性,可以把最小割后的残量网络的\(S\)集合和\(T\)集合找出来。
枚举\(S\)集合和\(T\)集合之间被割掉的边,求它们的权值和。
跟最小割进行对比,如果相等,则具有唯一性。
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <climits>
#include <vector>
#define N 410
#define M 4010
int n,m;
int a[N];
struct EDGE{
int to,len;
EDGE *las;
} e[M*2];
int ne;
EDGE *last[N*2];
inline void link(int u,int v,int len){
e[ne]={v,len,last[u]};
last[u]=e+ne++;
}
long long dis[N+M];
struct EDGE2{
int to,c;
EDGE2 *las;
} e2[M*4];
int ne2;
EDGE2 *last2[N+M];
#define rev(ei) (e2+(int(ei-e2)^1))
inline void link2(int u,int v,int c){
e2[ne2]={v,c,last2[u]};
last2[u]=e2+ne2++;
e2[ne2]={u,0,last2[v]};
last2[v]=e2+ne2++;
}
int S,T;
inline void S_P(){
static int q[100001];
static bool inq[N];
int head=0,tail=1;
q[1]=1;
memset(inq,0,sizeof inq);
inq[1]=1;
memset(dis,127,sizeof dis);
dis[1]=0;
do{
int x=q[++head];
for (EDGE *ei=last[x];ei;ei=ei->las)
if (dis[x]+ei->len<dis[ei->to]){
dis[ei->to]=dis[x]+ei->len;
if (!inq[ei->to]){
inq[ei->to]=1;
q[++tail]=ei->to;
}
}
inq[x]=0;
}
while (head!=tail);
memset(last2,0,sizeof last2);
ne2=0;
S=1,T=n;
for (int i=1;i<=T;++i){
for (EDGE *ei=last[i];ei;ei=ei->las)
if (dis[i]+ei->len==dis[ei->to]){
++n;
link2(i,n,a[i]);
link2(n,ei->to,a[ei->to]);
}
}
}
bool BZ;
int gap[N+M];
EDGE2 *cur[N+M];
int dfs(int x,int s){
if (x==T)
return s;
int have=s;
for (EDGE2 *ei=cur[x];ei;ei=ei->las){
cur[x]=ei;
if (ei->c && dis[ei->to]+1==dis[x]){
int t=dfs(ei->to,min(ei->c,have));
ei->c-=t,rev(ei)->c+=t,have-=t;
if (!have)
return s;
}
}
cur[x]=last2[x];
if (!--gap[dis[x]])
BZ=0;
dis[x]++;
gap[dis[x]]++;
return s-have;
}
inline long long flow(){
long long res=0;
memset(gap,0,sizeof gap);
memset(dis,0,sizeof dis),
gap[0]=n;
BZ=1;
while (BZ)
res+=dfs(S,INT_MAX);
return res;
}
inline bool pd(int mincut){
static int q[N+M];
static int vis[N+M];
int head=0,tail=1;
q[1]=S;
memset(vis,0,sizeof vis);
vis[S]=1;
do{
int x=q[++head];
for (EDGE2 *ei=last2[x];ei;ei=ei->las)
if (ei->c && !vis[ei->to]){
vis[ei->to]=1;
q[++tail]=ei->to;
}
}
while (head!=tail);
head=0,tail=1;
q[1]=T;
vis[T]=2;
do{
int x=q[++head];
for (EDGE2 *ei=last2[x];ei;ei=ei->las)
if (rev(ei)->c && !vis[ei->to]){
vis[ei->to]=2;
q[++tail]=ei->to;
}
}
while (head!=tail);
long long sum=0;
for (int i=1;i<=tail;++i)
for (EDGE2 *ei=last2[q[i]];ei;ei=ei->las)
if (rev(ei)->c==0 && vis[ei->to]==1)
sum+=ei->c;
return sum==mincut;
}
int main(){
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
int T;
scanf("%d",&T);
while (T--){
scanf("%d%d",&n,&m);
for (int i=1;i<n;++i)
scanf("%d",&a[i]);
a[n]=INT_MAX;
memset(last,0,sizeof last);
ne=0;
for (int i=1;i<=m;++i){
int u,v,len;
scanf("%d%d%d",&u,&v,&len);
link(u,v,len),link(v,u,len);
}
S_P();
long long mincut=flow();
if (pd(mincut))
printf("Yes %d\n",mincut);
else
printf("No %d\n",mincut);
}
return 0;
}
总结
这题的最大收获就是唯一性的判定了……
[JZOJ3348] 【NOI2013模拟】秘密任务的更多相关文章
- 【NOI2013模拟】坑带的树(仙人球的同构+圆方树乱搞+计数+HASH)
[NOI2013模拟]坑带的树 题意: 求\(n\)个点,\(m\)条边的同构仙人球个数. \(n\le 1000\) 这是一道怎么看怎么不可做的题. 这种题,肯定是圆方树啦~ 好,那么首先转为广义圆 ...
- [NOI2013模拟] BZOJ4705 棋盘游戏 解题报告(组合计数)
莫名打不开这道题的链接,请读者自行搜索 Description 有一个N*M的棋盘,初始每个格子都是白色的.行操作是指选定某一行,将这行所有格子的颜色取反(黑白互换).列操作是指选定某一列,将这列所有 ...
- [JZOJ3362] 【NOI2013模拟】数数
题目 题目大意 求区间\([A,B]\)有多少个数是"完美的". 一个数是"完美的",当且仅当这个数的各位能分成两个集合,使得两个集合中数字的和相等. \(B\ ...
- [JZOJ3347] 【NOI2013模拟】树的难题
题目 题目大意 给你一棵树,每个节点有三种黑.白.灰三种颜色. 你要割掉一些边(每条边被割需要付出一定的代价),使得森林的每棵树满足: 没有黑点或至多一个白点. 思考历程 这题一看就知道是一个树形DP ...
- [JZOJ3339]【NOI2013模拟】wyl8899和法法塔的游戏
题目 题目大意 给你一个数列,每次给出\(r,a,b\),你要找到\(l\in [a,b]\)使得\([l,r-1]\)的异或和最小, 并且要修改\(r\)位置的数. 思考历程 当我看到这题的时候,已 ...
- [JZOJ3337] 【NOI2013模拟】wyl8899的TLE
题目 题目大意 给你两个字符串\(A\)和\(B\),可以修改\(A\)中的一个字符,求修改后最长的\(A\)的前缀,使它是\(B\)的子串. 思考历程 看到这道题之后,第一眼想到的就是后缀自动机! ...
- 忘记秘密利用python模拟登录暴力破解秘密
忘记秘密利用python模拟登录暴力破解秘密: #encoding=utf-8 import itertools import string import requests def gen_pwd_f ...
- JZOJ 4272. 【NOIP2015模拟10.28B组】序章-弗兰德的秘密
272. [NOIP2015模拟10.28B组]序章-弗兰德的秘密 (File IO): input:frand.in output:frand.out Time Limits: 1000 ms M ...
- [jzoj 5781]【NOIP提高A组模拟2018.8.8】秘密通道 (最短路)
传送门 Description 有一副nm的地图,有nm块地,每块是下列四种中的一种: 墙:用#表示,墙有4个面,分别是前面,后面,左面,右面. 起点:用C表示,为主角的起点,是一片空地. 终点:用F ...
随机推荐
- Effective C++之条款2:尽量以const enum inline替换 #define
本文的标题也可以改成“用编译器替换预处理器”: const double AspectRatio = 1.653; //最好使用上述代码替换下述代码: #define ASPECT_RATIO 1.6 ...
- openwrt usb
fdisk -l #以列表的形式,列出当前挂载盘的情况 for 属性规定 label 与哪个表单元素绑定 <form> <label for="male"> ...
- vue computed和methods 计算属性和侦听器
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- nacos注册中心配置命名服务不生效问题
nacos作为注册中心指定命名空间,配置如下: 但是启动之后发现服务都默认注册到了public这个命名空间下面,也就是指定的命名空间不生效 这是因为注册中心使用的命名空间的配置不是nacos.conf ...
- BOM的介绍
BOM的概念 BOM(Browser Object Model) 是指浏览器对象模型,浏览器对象模型提供了独立于内容的.可以与浏览器窗口进行互动的对象结构.BOM由多个对象组成,其中代表浏览器窗口的W ...
- PHP ftp_rename() 函数
定义和用法 ftp_rename() 函数重命名 FTP 服务器上的文件或目录. 如果成功,该函数返回 TRUE.如果失败,则返回 FALSE. 语法 ftp_rename(ftp_connectio ...
- 单调栈(最大子矩形强化版)——牛客多校第八场A
求01矩阵里有多少个不同的1矩阵 首先预处理出pre[i][j]表示i上面连续的1个数,对每行的高度进行单调栈处理 栈里的元素维护两个值:pre[i][j]和向前延伸最多能维护的位置pos 然后算贡献 ...
- Delphi操作ACCESS技巧集
1.DELPHI中操作access数据库(建立.mdb文件,压缩数据库)以下代码在WIN2K,D6,MDAC2.6下测试通过,编译好的程序在WIN98第二版无ACCESS环境下运行成功.//在之前us ...
- random,time,sys,os,序列化模块
random模块(随机数模块) 取随机小数: random.random() 取0-1之间的小数 random.uniform(x, y) 取x-y之间的小数 取随机整数: random.randin ...
- JVM内核-原理、诊断与优化学习笔记(八):JAVA堆分析
文章目录 内存溢出(OOM)的原因 在JVM中,有哪些内存区间? 堆溢出 永久区 Java栈溢出 直接内存溢出 小问题? MAT使用基础 柱状图显示 支配树 显示线程信息 显示堆总体信息,比如消耗最大 ...