01 分数规划
1.随机化算法2.组合数学3.概率和期望4.树链剖分5.矩阵乘法与矩阵快速幂6.最短路7.卡特兰数、Prüfer 序列、BSGS8.分块和莫队9.AC 自动机10.平衡树11.基础字符串算法12.基础数论13.Miller-Rabin 与 Pollard-Rho14.广义后缀自动机15.后缀自动机 SAM16.回文自动机 PAM17.Manacher18.后缀数组
19.01 分数规划
20.网络流21.整体二分22.cdq 分治23.点分治24.虚树25.扫描线26.笛卡尔树27.基环树28.树哈希29.莫比乌斯反演30.二分图31.朱刘算法32.最大团33.杂项34.杜教筛35.拉格朗日插值36.线段树综合37.可持久化数据结构38.K-D Tree39.Burnside 引理与 Polya 定理40.线性基41.替罪羊树42.LCT43.插头 dp44.原根45.多项式乘法46.斯特林数47.二项式反演与斯特林反演48.Min-Max 容斥49.辛普森积分法50.Min_25 筛51.凸包52.2-SAT1 问题概述
分数规划是用于求一类分式的极值问题。
给定两个数列
再说直白点就是每个物品有
2 解法
解决 01 分数规划问题的通法就是二分。下面以最大值举例说明。
我们二分一个答案
所以我们只需要求出
下面举一些例子来说明 01 分数规划的题目的特征。
3 实例
3.1 [USACO18OPEN] Talent Show G
首先转化题目模型如下:
求出
的最大值,要满足 。
发现要求式子就是 01 分数规划的标准形式,现在问题是怎样求
仔细思考一下我们不难发现,如果我们构造一个物品,体积为
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int Maxn = 2e5 + 5;
const int Inf = 2e9;
const int base = 10000;
int n, W;
int w[Maxn], t[Maxn];
int sum = 0, sw = 0;
int dp[255][2505];
bool check(int x) {
memset(dp, 128, sizeof dp);
dp[0][0] = 0;
for(int i = 0; i < n; i++) {
for(int j = 0; j <= W; j++) {
int k = min(W, j + w[i + 1]);
dp[i + 1][k] = max(dp[i + 1][k], dp[i][j] + t[i + 1] - x * w[i + 1]);
dp[i + 1][j] = max(dp[i + 1][j], dp[i][j]);
}
}
return dp[n][W] > 0;
}
int ans = 0;
void bs() {
int l = 0, r = sum, mid;
while(l <= r) {
mid = (l + r) >> 1;
if(check(mid)) {
ans = mid;
l = mid + 1;
}
else {
r = mid - 1;
}
}
}
signed main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> W;
for(int i = 1; i <= n; i++) {
cin >> w[i] >> t[i];
t[i] *= base;
sum += t[i];
sw += w[i];
}
bs();
cout << ans / 10;
return 0;
}
3.2 [HNOI2009] 最小圈
首先转化模型如下:
每一条边上有两个权值
,且 。求出一个环使得 最小。
显然这又是一个 01 分数规划问题,我们最后转化出的式子应该是
我们将边权赋为
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int Maxn = 2e5 + 5;
const int Inf = 2e9;
int n, m;
struct Edge {
int u, v;
double w;
}ed[Maxn];
int head[Maxn], edgenum;
struct node {
int nxt, to;
double w;
}edge[Maxn];
void add(int u, int v, double w) {
edge[++edgenum] = {head[u], v, w};
head[u] = edgenum;
}
double dis[Maxn];
bool vis[Maxn];
bool SPFA(int x) {
vis[x] = 1;
for(int i = head[x]; i; i = edge[i].nxt) {
int to = edge[i].to;
double w = edge[i].w;
if(dis[x] + w < dis[to]) {
dis[to] = dis[x] + w;
if(vis[to] || SPFA(to)) {
return 1;
}
}
}
vis[x] = 0;
return 0;
}
int check(double x) {
edgenum = 0;
for(int i = 1; i <= n; i++) {
head[i] = 0;
}
for(int i = 1; i <= m; i++) {
add(ed[i].u, ed[i].v, ed[i].w - x);
}
for(int i = 1; i <= n; i++) {
dis[i] = 0;
vis[i] = 0;
}
for(int i = 1; i <= n; i++) {
if(SPFA(i)) {
return 1;
}
}
return 0;
}
double bs() {
double l = -1e7, r = 1e7, mid;
while(r - l >= 1e-9) {
mid = (l + r) / 2.0;
if(check(mid)) {
r = mid;
}
else {
l = mid;
}
}
return l;
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
cin >> n >> m;
for(int i = 1; i <= m; i++) {
cin >> ed[i].u >> ed[i].v >> ed[i].w;
add(ed[i].u, ed[i].v, ed[i].w);
}
double res = bs();
cout << fixed << setprecision(8) << res ;
return 0;
}
通过上述实例不难发现,当题目中出现两个数列和之比,也就是形如
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!