题目

现在,保密成为一个很重要也很困难的问题。如果没有做好,后果是严重的。比如,有个人没有自己去修电脑,又没有拆硬盘,后来的事大家都知道了。

当然,对保密最需求的当然是军方,其次才是像那个人。为了应付现在天上飞来飞去的卫星,军事基地一般都会建造在地下。

某K国的军事基地是这样子的:地面上两排大天井共n1个作为出入口,内部是许多除可以共享出入口外互不连通的空腔,每个空腔有且只有两个出入口,并且这两个出入口不会在同一排。为了方便起见,两排出入口分别编号为1,3,5…和2,4,6…并且最大的编号为n1。

虽然上面扯了那么多关于保密的东西,但是其实解密也是一件很纠结的事情。但其实最简单直接暴力无脑的解密方法就是找个人去看看。。。

我们有很牛X的特种部队,只需要派出一支特种部队到K国基地的某个出入口,那么和这个出入口直接相连的所有空腔都可以被探索,但也只有这些空腔可以被这支部队探索。现在有足够多的特种部队可以供你调遣,你必须使用他们调查完所有的K国基地内的空腔。

当然,你的基地离K国基地不会太近,周边的地图将会给你,表示为n个检查点和m条连接这些点的道路,其中点1到点n1就是K国基地的出入口,点n是你的部队的出发点。对每条道路,有不同的通行时间t和安全系数s。因为情报部门只对单向的道路安全系数进行了评估,所以这些道路只允许单向通行,并且不会存在环。

一支特种部队从你的基地出发,通过某条路径,到达某个K国基地出入口,此时这支部队的危险性表示为总时间和这条路径经过的所有道路的安全系数和的比值。整个行动的危险性表示为你派出的所有部队的危险性之和。你需要使这个值最小的情况下探索整个K国基地。

快点完成这个任务,在K国的叫兽宣布你是K国人之前。

输入格式

第一行2个正整数n,m (4 <= n <= 700, m <= 100000) 表示整个地区地图上的检查点和道路数。

下面m行,每行4个正整数a, b, t, s(a, b <=n, 1 <= t, s <= 10)表示一条从a到b的道路需时为t,安全系数为s。

接下来1行2个正整数m1和n1(m1 <= 40000, n1 < min{n, 161}), m1表示K国基地空腔的个数,n1表示K国基地出入口的个数。

再接下来m1行,每行2个正整数u, v (u, v<=n1, u是奇数,v是偶数),表示每个空腔的2个出入口。

输出格式

一行,最小的危险性,保留一位小数。或者输出”-1”(无引号)表示此任务不可能完成。

输入样例

5 5

5 1 10 1

5 1 10 1

5 2 9 1

5 3 7 1

5 4 8 1

4 4

1 2

1 4

3 2

3 4

输出样例

17.0

题解

每个空腔有两个入口,二者必选一

显然到达每个点都是有一个固定的最优代价

显然这就是一个最小边权覆盖,用网络流即可

现在问题转化为了求\(n1\)中每个点的最小代价

比值最小,显然是\(01\)分数规划

我们二分那个最小值,用SPFA判一下是否是负的就好了

【剪枝】在SPFA过程中,如果那个点的最短路已经为负,直接返回

QAQ二分边界设错了查了半天

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<algorithm>
#define eps 1e-9
#define LL long long int
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
using namespace std;
const int maxn = 705,maxm = 200005,INF = 1000000000;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
struct FLOW{
int to[maxm],nxt[maxm],ne,h[maxn],cur[maxn],vis[maxn],d[maxn],S,T;
double f[maxm];
FLOW(){ne = 2;}
void build(int u,int v,double w){
to[ne] = v; nxt[ne] = h[u]; f[ne] = w; h[u] = ne++;
to[ne] = u; nxt[ne] = h[v]; f[ne] = 0; h[v] = ne++;
}
bool bfs(){
queue<int> q;
memset(d,0,sizeof(d));
memset(vis,0,sizeof(vis));
int u,t;
q.push(S); d[S] = 0; vis[S] = true;
while (!q.empty()){
u = q.front(); q.pop();
for (int k = h[u]; k; k = nxt[k]){
if (fabs(f[k]) > eps && !vis[t = to[k]]){
d[t] = d[u] + 1; vis[t] = true;
if (t == T) return true;
q.push(t);
}
}
}
return vis[T];
}
double dfs(int u,double minf){
if (fabs(minf) < eps || u == T) return minf;
int t;
double ff,flow = 0;
if (cur[u] == -1) cur[u] = h[u];
for (int& k = cur[u]; k; k = nxt[k])
if (d[t = to[k]] == d[u] + 1 && fabs(ff = dfs(t,min(minf,f[k]))) > eps){
f[k] -= ff; f[k ^ 1] += ff;
flow += ff; minf -= ff;
if (fabs(minf) < eps) break;
}
return flow;
}
double maxflow(){
double flow = 0;
while (bfs()){
for (int i = 0; i <= T; i++) cur[i] = -1;
flow += dfs(S,INF);
}
return flow;
}
}G;
int h[maxn],ne = 2;
struct EDGE{int to,nxt; double t,s;}ed[maxm];
inline void build(int u,int v,double t,double s){
ed[ne] = (EDGE){v,h[u],t,s}; h[u] = ne++;
}
int n,m,n1,m1,reach[maxn],inq[maxn];
double ri[maxn],d[maxn];
void bfs(){
queue<int> q;
q.push(n); reach[n] = true;
int u;
while (!q.empty()){
u = q.front(); q.pop();
Redge(u) if (!reach[to = ed[k].to]){
reach[to] = true;
q.push(to);
}
}
}
bool spfa(double e,int T){
queue<int> q; q.push(n);
for (int i = 1; i < n; i++) d[i] = INF,inq[i] = false;
d[n] = 0;
int u;
while (!q.empty()){
u = q.front(); q.pop();
inq[u] = false;
Redge(u) if (d[to = ed[k].to] > d[u] + (ed[k].t - e * ed[k].s)){
d[to] = d[u] + (ed[k].t - e * ed[k].s);
if (to == T && d[to] <= eps) return true;
if (!inq[to]) inq[to] = true,q.push(to);
}
}
return d[T] < eps;
}
void work1(){
for (int i = 1; i <= n1; i++){
if (!reach[i]){
ri[i] = INF;
continue;
}
double l = 0,r = 1000,mid;
while (r - l > 0.00001){
mid = (l + r) / 2;
if (spfa(mid,i)) r = mid;
else l = mid;
}
ri[i] = (l + r) / 2;
}
}
int main(){
n = read(); m = read();
int u,v,t,s;
while (m--){
u = read(); v = read(); t = read(); s = read();
build(u,v,t,s);
}
bfs();
m1 = read(); n1 = read();
work1();
G.S = 0; G.T = n1 + 1;
for (int i = 1; i <= n1; i++)
if (i & 1) G.build(G.S,i,ri[i]);
else G.build(i,G.T,ri[i]);
for (int i = 1; i <= m1; i++){
u = read(); v = read();
if (v & 1) swap(u,v);
if (!reach[u] && !reach[v]){
puts("-1");
return 0;
}
G.build(u,v,INF);
}
printf("%.1lf\n",G.maxflow());
return 0;
}

BZOJ2285 [SDOI2011]保密 【01分数规划 + 网络流】的更多相关文章

  1. 【BZOJ2285】[SDOI2011]保密(分数规划,网络流)

    [BZOJ2285][SDOI2011]保密(分数规划,网络流) 题面 BZOJ 洛谷 题解 首先先读懂题目到底在干什么. 发现要求的是一个比值的最小值,二分这个最小值\(k\),把边权转换成\(t- ...

  2. 【洛谷P2494】 [SDOI2011]保密(分数规划+最小割)

    洛谷 题意: 题意好绕好绕...不想写了. 思路: 首先类似于分数规划做法,二分答案得到到每个点的最小危险度. 然后就是在一个二分图中,两边撤掉最少的点(相应代价为上面算出的危险度)及相应边,使得中间 ...

  3. 洛谷2494 [SDOI2011]保密 (分数规划+最小割)

    自闭一早上 分数规划竟然还能被卡精度 首先假设我们已经知道了到每个出入口的时间(代价) 那我们应该怎么算最小的和呢? 一个比较巧妙的想法是,由于题目规定的是二分图. 我们不妨通过最小割的形式. 表示这 ...

  4. bzoj 1312: Hard Life 01分数规划+网络流

    题目: Description 在一家公司中,人事部经理与业务部经理不和.一次,总经理要求人事部从公司的职员中挑选出一些来帮助业务部经理完成一项任务.人事部经理发现,在公司的所有职员中,有一些人相处得 ...

  5. [转]01分数规划算法 ACM 二分 Dinkelbach 最优比率生成树 最优比率环

    01分数规划 前置技能 二分思想最短路算法一些数学脑细胞? 问题模型1 基本01分数规划问题 给定nn个二元组(valuei,costi)(valuei,costi),valueivaluei是选择此 ...

  6. bzoj 4501: 旅行 01分数规划+概率期望dp

    题目大意: http://www.lydsy.com/JudgeOnline/problem.php?id=4501 题解: 首先我们不考虑可以删除边的情况下,如何计算期望边数. 然后我们发现这是个有 ...

  7. POJ3621Sightseeing Cows[01分数规划 spfa(dfs)负环 ]

    Sightseeing Cows Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9703   Accepted: 3299 ...

  8. ZOJ 2676 Network Wars ★(最小割算法介绍 && 01分数规划)

    [题意]给出一个带权无向图,求割集,且割集的平均边权最小. [分析] 先尝试着用更一般的形式重新叙述本问题.设向量w表示边的权值,令向量c=(1, 1, 1, --, 1)表示选边的代价,于是原问题等 ...

  9. POJ 2728 Desert King ★(01分数规划介绍 && 应用の最优比率生成树)

    [题意]每条路径有一个 cost 和 dist,求图中 sigma(cost) / sigma(dist) 最小的生成树. 标准的最优比率生成树,楼教主当年开场随手1YES然后把别人带错方向的题Orz ...

随机推荐

  1. UVA 1153 Keep the Customer Satisfied 顾客是上帝(贪心)

    因为每增加一个订单,时间是会增加的,所以先按截止时间d排序, 这样的话无论是删除一个订单,或者增加订单,都不会影响已经选好的订单. 然后维护一个已经选好的订单的大根堆(优先队列),如果当前无法选择的话 ...

  2. MySQL8 Authentication plugin 'caching_sha2_password' cannot be loaded

    这是因为mysql8 和以前密码的验证方式不同,可以先从命令行进入     MySQL  -uroot -p       然后输入 ALTER USER 'root'@'localhost' IDEN ...

  3. 2018.5.9 Oracle数据库查询命令

    0.查询所有数据(最简单,但是时间很久) select * from emp; Result: EMPNO ENAME JOB MGR HIREDATE SAL COMM DEPTNO ----- - ...

  4. PAT (Basic Level) Practise (中文)- 1010. 一元多项式求导 (25)

    http://www.patest.cn/contests/pat-b-practise/1010 设计函数求一元多项式的导数.(注:xn(n为整数)的一阶导数为n*xn-1.) 输入格式:以指数递降 ...

  5. word中在空白处加下划线不显示解决

    终极解决:Ctrl + Shift + Space Alt + 选择,竖向选择.和VS,其他一些编辑器一样

  6. redis基础知识学习

    数据结构:1.String 添加: set key value get key getset key value (先get再set) incr key (key对应value原子性递增1) decr ...

  7. 【转】再谈 最速下降法/梯度法/Steepest Descent

    转载请注明出处:http://www.codelast.com/ 最速下降法(又称梯度法,或Steepest Descent),是无约束最优化领域中最简单的算法,单独就这种算法来看,属于早就“过时”了 ...

  8. MySQL中文转换成拼音的函数

    CREATE DEFINER=`root`@`localhost` FUNCTION `fristPinyin`(`P_NAME` VARCHAR(255) CHARSET utf8) RETURNS ...

  9. 使用TensorFlow的卷积神经网络识别手写数字(2)-训练篇

    import numpy as np import tensorflow as tf import matplotlib import matplotlib.pyplot as plt import ...

  10. go语言结构体作为函数参数,采用的是值传递

    经过验证,go语言结构体作为函数参数,采用的是值传递.所以对于大型结构体传参,考虑到值传递的性能损耗,最好能采用指针传递. 验证代码: package main import ( "fmt& ...