## 问题描述

  首先分数规划是一类决策性问题

  一般形式是:

\[\lambda=\frac{f(x)}{g(x)}
\]

  其中\(f(x)\)和\(g(x)\)都是连续的实值函数,然后要求\(\lambda\)的最大值或最小值

​  

  这类问题中,研究较多的是\(01\)分数规划,也就是求

\[\lambda=\frac{\sum (f_i*x_i)}{\sum (g_i*x_i)}
\]

  其中\(x_i \in \{0,1\}\),其他条件和普通分数规划一样,求\(\lambda\)的最大或最小值

​  接下来我们讨论的是\(01\)分数规划

  

具体求解

  求解\(01\)分数规划的问题很重要的一个思想就是二分

  某种程度上可以理解为一种二分答案,只是判断的方式稍微有一点点不同

  我们处理一下上面的\(\lambda\)的表达式:

\[\begin{aligned}
\sum(f_i*x_i)&=\lambda \sum(g_i*x_i)\\
\end{aligned}
\]

  移一下项变成:

\[\sum(f_i*x_i)-\lambda\sum(g_i*x_i)=0
\]

​  这个就是我们需要的一个式子啦

  

  具体什么意思呢?

​  以求解表达式的最大值为例,考虑二分最终的答案

​  我们将最终的答案记为\(ans\),记当前二分到的\(mid\)为\(\lambda'\),那么上面这个表达式应该满足:

1、\(ans<\lambda'\)时,\(max(\frac{\sum (f_i*x_i)}{\sum (g_i*x_i)})=ans<\lambda'\),也就是\(max(\sum(f_i*x_i)-\lambda’\sum(g_i*x_i))<0\)

2、\(ans=\lambda'\)时,则上面这个表达式的值为\(0\)

3、\(ans>\lambda'\)时,则上面这个表达式的值\(>0\)

  

​  所以我们要做的就是在一个比较合理的时间内求出\(max(\sum(f_i*x_i)-\lambda’\sum(g_i*x_i))\)(或者\(min\))就好啦

​  这样的题目往往会跟一些其他的算法结合起来,比如环啊生成树啊之类的

​  接下来放几道例题帮助理解

  

例题们

  首先是两道相对来说基础一点的:

Portal -->bzoj4819新生舞会

​  看到答案的那个形式。。那就分数规划咯。。

​  我们现在相当于是要求:

\[\frac{\sum\limits_{i=1}^{n} \sum\limits_{j=1}^n a_{i,j}*x_{i,j}}{\sum\limits_{i=1}^{n} \sum\limits_{j=1}^n b_{i,j}*x_{i,j}}
\]

​  这个东西的最大值

​  其中\(x_{i,j}\in \{0,1\}\)表示\(i\)和\(j\)是否是舞伴

​  那明显是一个\(01\)分数规划的形式,套用上面讲到的方法,现在问题转变成如何判断

\[max(\sum\limits_{i=1}^{n} \sum\limits_{j=1}^n a_{i,j}*x_{i,j}-\lambda'\sum\limits_{i=1}^{n} \sum\limits_{j=1}^n b_{i,j}*x_{i,j})
\]

​  与\(0\)的关系

  

​  这里我们可以考虑用费用流来求解,具体建图相对来说还是比较好想的:

​  男生看成\(1\)到\(n\)号,女生看成\(1+n\)到\(n+n\)号

1、源点\(S\)往\(1\)到\(n\)(男生)都连一条费用为\(0\),流量为\(1\)的边

2、男生\(i\)(也就是\(i\)号点)往女生\(j\)(也就是\(j+n\)号点)连一条费用为\((a_{i,j}-\lambda' b_{i,j})\),流量为\(1\)的边

3、\(1+n\)到\(n+n\)号(女生)往汇点\(T\)连一条费用为\(0\),流量为\(1\)的边

  然后大力跑最大费用最大流就好啦

  

  代码大概长这个样子:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define ll long long
using namespace std;
const int N=110,inf=2147483647;
const double eps=1e-8;
struct xxx{
int x,y,nxt,r;
double c;
}a[N*N*10+10];
queue<int> q;
int h[N*2],pre[N*2];
double cost[N*2];
bool vis[N*2];
int A[N][N],B[N][N];
int n,m,tot,S,T;
void add(int x,int y,double c,int r);
bool spfa(double &rec);
void build(double mid);
void solve(); int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d",&n);
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
scanf("%d",&A[i][j]);
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
scanf("%d",&B[i][j]);
solve();
} void add(int x,int y,double c,int r){
//printf("%d %d %.6lf %d\n",x,y,c,r);
a[++tot].y=y; a[tot].x=x; a[tot].nxt=h[x]; h[x]=tot; a[tot].r=r; a[tot].c=c;
a[++tot].y=x; a[tot].x=y; a[tot].nxt=h[y]; h[y]=tot; a[tot].r=0; a[tot].c=-c;
} bool spfa(double &rec){
while (!q.empty()) q.pop();
int v,u;
q.push(S); cost[S]=0;
pre[S]=-1;
for (int i=S+1;i<=T;++i) cost[i]=-inf,vis[i]=false;
vis[S]=true;
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) continue;
if (cost[u]<cost[v]+a[i].c){
cost[u]=cost[v]+a[i].c;
pre[u]=i;
if (!vis[u])
vis[u]=true,q.push(u);
}
}
vis[v]=false;
}
if (cost[T]==-inf) return false;
int flow=inf;
u=T;
while (pre[u]!=-1)
flow=min(flow,a[pre[u]].r),u=a[pre[u]].x;
rec+=1.0*flow*cost[T];
u=T;
while (pre[u]!=-1)
a[pre[u]].r-=flow,a[pre[u]^1].r+=flow,u=a[pre[u]].x;
return true;
} void build(double mid){
tot=-1;
S=0; T=2*n+1;
for (int i=S;i<=T;++i) h[i]=-1;
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
add(i,j+n,1.0*A[i][j]-mid*B[i][j],1);
for (int i=1;i<=n;++i)
add(S,i,0,1),add(i+n,T,0,1);
} bool check(double mid){
double rec=0;
build(mid);
while (spfa(rec));
return rec>0;
} void solve(){
double l=0,r=10000,mid,ans;
while (r-l>eps){
mid=(l+r)*0.5;
if (check(mid)) ans=mid,l=mid;
else r=mid;
}
printf("%.6lf\n",ans);
}

  

  

Portal -->bzoj1690奶牛的旅行

​  (啊好吧这题是权限题qwq)

  题意的话。。简单来说就是:给你一个有向图,每条边有一个边权,每个点有一个点权,求一个环满足\(\frac{\sum 点权}{\sum 边权}\) 最大,路径中至少含有两个点(也就是保证\(\sum\)边权不能为\(0\))

​  

​  首先我们分析一下最后选出来的环有没有可能是一个复合环

  粗略想一下。。如果说是一个复合环的话,那么完全可以通过去掉一些路径变成一个简单环并且使得经过的点不减少

  所以最后选出来的肯定是一个简单环

​  

  那么问题就转化成了求一个比值最大的简单环,这个就可以用\(01\)分数规划来解决了

​  那么也就是说我们现在要求一个环的:

\[max(\sum点权-\lambda'\sum边权)
\]

​  与\(0\)的关系

​  那么就每次建一个新图,把原图中的\((点权-\lambda' 边权)\) 设成新图的边权,然后用spfa判断一下是否存在正环就好了

  

​  代码大概长这个样子:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int N=1010,M=5010,inf=2147483647;
const double eps=1e-3;
struct xxx{
int y,nxt;
double dis;
}a[M*2];
struct Data{
int x,y,t;
}rec[M];
queue<int> q;
int h[N],val[N],cnt[N];
double cost[N];
bool vis[N];
int n,m,tot,S,T;
void add(int x,int y,double c);
bool spfa();
void build(double mid);
bool check(double mid);
void solve(); int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i) scanf("%d",val+i);
for (int i=1;i<=m;++i)
scanf("%d%d%d",&rec[i].x,&rec[i].y,&rec[i].t);
solve();
} void add(int x,int y,double c){
//printf("%d %d %.2lf\n",x,y,c);
a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot; a[tot].dis=c;
} bool spfa(){
while (!q.empty()) q.pop();
int u,v;
for (int i=S;i<=T;++i) cost[i]=0,vis[i]=true,q.push(i),cnt[i]=0;
while (!q.empty()){
v=q.front(); q.pop();
for (int i=h[v];i!=-1;i=a[i].nxt){
u=a[i].y;
if (cost[u]<cost[v]+a[i].dis){
cost[u]=cost[v]+a[i].dis;
if (!vis[u]){
q.push(u),vis[u]=true;
++cnt[u];
if (cnt[u]>n) return true;
}
}
}
vis[v]=false;
}
return false;
} bool check(double mid){
build(mid);
return spfa();
} void solve(){
double l=0,r=1000,mid;
while (r-l>eps){
mid=(l+r)*0.5;
if (check(mid)) l=mid;
else r=mid;
}
printf("%.2lf\n",l);
} void build(double mid){
tot=0; S=0; T=n+1;
for (int i=S;i<=T;++i) h[i]=-1;
for (int i=1;i<=m;++i)
add(rec[i].x,rec[i].y,1.0*val[rec[i].x]-1.0*rec[i].t*mid);
}

  

  

​  然后是两道相对来说思考量或者码量大一点的,因为。。篇幅可能会比较长所以新开两篇博来写了,这里就放博客的传送门嗯

Portal -->bzoj4898商旅

Portal -->bzoj2402陶陶的难题II

  

总的来说

  其实感觉。。\(01\)分数规划更多的是一种转化问题的思想?

  运用起来还是很灵活的,可以跟各种东西套在一起。。

  大概就是这样吧ovo

【learning】01分数规划的更多相关文章

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

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

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

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

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

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

  4. 【Earthquake, 2001 Open 】 0-1 分数规划

    71  奶牛施工队一场地震把约翰家园摧毁了,坚强的约翰决心重建家园.约翰已经修复了 N 个牧场,他需要再修复一些道路把它们连接起来.碰巧的是,奶牛们最近也成立了一个工程队,专门从事道路修复.而然,奶牛 ...

  5. POJ 2976 Dropping tests 01分数规划

    给出n(n<=1000)个考试的成绩ai和满分bi,要求去掉k个考试成绩,使得剩下的∑ai/∑bi*100最大并输出. 典型的01分数规划 要使∑ai/∑bi最大,不妨设ans=∑ai/∑bi, ...

  6. 【转】[Algorithm]01分数规划

    因为搜索关于CFRound277.5E题的题解时发现了这篇文章,很多地方都有值得借鉴的东西,因此转了过来 原文:http://www.cnblogs.com/perseawe/archive/2012 ...

  7. codevs 1183 泥泞的道路 01分数规划

    题目链接 题目描述 Description CS有n个小区,并且任意小区之间都有两条单向道路(a到b,b到a)相连.因为最近下了很多暴雨,很多道路都被淹了,不同的道路泥泞程度不同.小A经过对近期天气和 ...

  8. Dropping tests(01分数规划)

    Dropping tests Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8176   Accepted: 2862 De ...

  9. POJ2728 最小比率生成树/0-1分数规划/二分/迭代(迭代不会)

    用01分数规划 + prime + 二分 竟然2950MS惊险的过了QAQ 前提是在TLE了好几次下过的 = = 题目意思:有n个村庄,村庄在不同坐标和海拔,现在要对所有村庄供水,只要两个村庄之间有一 ...

随机推荐

  1. dubbo SpringContainer

    dubbo SpringContainer Spring启动类容器 SPI service provider interfaces 服务提供借口 Singleton 单例 ThreadSafe 线程安 ...

  2. 搭建RTSP服务器时nginx的nginx.conf文件配置

    worker_processes 1; events { worker_connections 1024;} http { include mime.types; default_type appli ...

  3. leetcode13_C++罗马数字转整数

    罗马数字包含以下七种字符: I, V, X, L,C,D 和 M. 字符 数值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000 例如, 罗马数字 2 写做 II ,即为两个并 ...

  4. eBay:美国各州最受欢迎的产品品类

    雨果网从美国媒体<商业内幕>8月26日的报道中获悉,电商巨头eBay近日发布了美国各州最受欢迎的产品品类.包括:加州人青睐女性高端配件,而新泽西 州的男人喜欢古龙香水.相比这些华丽配饰而言 ...

  5. 印度电商Snapdeal获投$1.34亿 eBay领投

    据消息人士透露,eBay领投1.337亿美元,投资印度最大在线购物网站Snapdeal,最终或有可能全权收购该网站.据悉,在此次投资中,大部分资金来自eBay. 今年1月,曾有报道称,Snapdeal ...

  6. python基础-02-while格式化逻辑运算

    python其他知识目录 1.循环打印“我是小马过河” while True:    print('我是小马过河') #4.用while从一打印到10 #5.请通过循环,1 2 3 4 5 6 8 9 ...

  7. react native基础与入门

    react native基础与入门 一.react native 的优点 1.跨平台(一才两用) 2.低投入高回报 (开发成本低.代码复用率高) 3.性能高:拥有独立的js渲染引擎,比传统的h5+ w ...

  8. 软工实践第八次作业(课堂实战)- 项目UML设计(第五组)

    本次作业博客 团队信息 队名:起床一起肝活队 原组长: 白晨曦(101) 原组员: 李麒 (123) 陈德斌(104) 何裕捷(214) 黄培鑫(217) 王焕仁(233) 林志华(128) 乐忠豪( ...

  9. Rsyslog-legacy(旧版本语法)配置说明及举例

    1. RULES-书写规则 格式:日志设备(类型).日志级别             日志处理方式 (1)日志类型分类 auth pam产生的日志 authpriv ssh,ftp等登录信息的验证信息 ...

  10. 结对编程--fault,error,failure的程序设计

    一.结对编程内容: 1.不能触发Fault. 2.触发Fault,但是不触发Error. 3.触发Error,但不触发Failure. 二.结对编程人员 1.周浩,周宗耀 2.结对截图: 三.结对项目 ...