01分数规划小记
update:
- 2024.7.10 补两道 分数规划 + 网络流的好题
01 分数规划
求形如 式子的最大值或最小值。
一般方法有两个:二分法与迭代法。这里不再赘述。
01分数规划时常与图论结合。
例题:
I P1570 KC 喝咖啡
令
二分法:
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 210;
const double eps = 1e-5;
//01分数规划
int n,m;
double a[N],b[N],c[N];
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)scanf("%lf",&a[i]);
for(int i = 1;i <= n;i++)scanf("%lf",&b[i]);
double l = 0,r = 1010;
while(l + eps < r){
double mid = (l + r) / 2.0;
for(int i = 1;i <= n;i++)c[i] = a[i] - mid * b[i];
sort(c+1,c+1+n);//排序找最大值
double s = 0;
for(int i = n;i > n-m;i--)s += c[i];
if(s >= 0)l = mid;
else r = mid;
}
printf("%.3lf\n",r);
return 0;
}
II P4377 [USACO18OPEN] Talent Show G
首先要求
我们把每个牛当做 质量为
点击查看代码
#include <bits/stdc++.h>
using namespace std;
//01分数规划 + 背包
#define ll long long
const int N = 300,M = 1010;
const double eps = 1e-5,inf = 1e8;
int n,W;
double w[N],t[N],f[M];
bool check(double mid){
for(int i = 1;i <= 1000;i++)f[i] = -inf;
for(int i = 1;i <= n;i++){
for(int j = W;j >= 0;j--){
int k = min(W,j+(int)w[i]);//超过的直接放到f[W]上
f[k] = max(f[k],f[j] + t[i] - mid * w[i]);
}
}
return f[W] >= 0;
}
int main(){
scanf("%d%d",&n,&W);
for(int i = 1;i <= n;i++)scanf("%lf%lf",&w[i],&t[i]);
double l = 0,r = 1e6;
while(l + eps < r){
double mid = (l + r) / 2;
if(check(mid))l = mid;
else r = mid;
}
printf("%d\n",int(r*1000));
return 0;
}
III P2868 [USACO07DEC] Sightseeing Cows G
一个图,有点权有边权,设一个环内点集为
最长路判正环!!(不会的去学-_-)(本题
然后正常二分即可。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2e3+10,M = 1e4+10;
const double eps = 1e-4,inf = 1e8;
//01分数规划 + 判负环
int n,m;
struct made{
int nx,ver;
double ed;
}e[M<<1];
int hd[N],tot;
double a[N];
void add(int x,int y,double z){
tot++;
e[tot].nx = hd[x],e[tot].ver = y,e[tot].ed = z,hd[x] = tot;
}
double d[N];
int in[N];bool v[N];
bool spfa(double mid){
memset(v,0,sizeof v);
memset(in,0,sizeof in);
for(int i = 0;i <= n;i++)d[i] = -inf;
queue<int>q;q.push(0),v[0] = 1,d[0] = 0;
while(!q.empty()){
int x = q.front();q.pop();
v[x] = 0;
for(int i = hd[x];i;i = e[i].nx){
int y = e[i].ver;double z = e[i].ed;
z = a[x] - mid * z;
if(d[y] < d[x] + z){
d[y] = d[x] + z;
in[y]++;
if(in[y] > n)return 1;//判正环
if(!v[y])v[y] = 1,q.push(y);
}
}
}
return 0;
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)scanf("%lf",&a[i]);
for(int i = 1;i <= n;i++)add(0,i,0);
for(int i = 1;i <= m;i++){
int x,y;double z;
scanf("%d%d%lf",&x,&y,&z);
add(x,y,z);
}
double l = 0,r = 1e5;
while(l + eps < r){
double mid = (l + r) / 2;
if(spfa(mid))l = mid;
else r = mid;
}
printf("%.2lf\n",r);
return 0;
}
IV P3199 [HNOI2009] 最小圈
我们要找图中一个环使得环上权值的平均值最小,即一个环的边集
做完了?没有,如果你直接写 开摆原神启动
有一个
时间复杂度不会,反正就是很快 (:з」∠),咕咕咕。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N = 3e3+10,M = 2e4+10;
const double eps = 1e-10,inf = 1e8;
//01分数规划 + 判负环
int n,m;
struct made{
int nx,ver;
double ed;
}e[M<<1];
int hd[N],tot;
void add(int x,int y,double z){
tot++;
e[tot].nx = hd[x],e[tot].ver = y,e[tot].ed = z,hd[x] = tot;
}
double d[N];
bool v[N];
bool spfa(int x,double mid){
v[x] = 1;
for(int i = hd[x];i;i = e[i].nx){
int y = e[i].ver;double z = e[i].ed;
z -= mid;
if(d[y] > d[x] + z){
d[y] = d[x] + z;
if(v[y] || spfa(y,mid))return 1;//被遍历过了即有负环
}
}
v[x] = 0;
return 0;
}//dfs-spfa判负环
bool check(double mid){
memset(v,0,sizeof v);
for(int i = 1;i <= n;i++)d[i] = 0;//初值为0
for(int i = 1;i <= n;i++)
if(spfa(i,mid))return 1;
return 0;
}
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i++)add(0,i,0);
for(int i = 1;i <= m;i++){
int x,y;double z;
scanf("%d%d%lf",&x,&y,&z);
add(x,y,z);
}
double l = -1e7,r = 1e7;
while(l + eps < r){
double mid = (l + r) / 2;
if(check(mid))r = mid;
else l = mid;
}
printf("%.8lf\n",r);
return 0;
}
V 3999. 制作人偶
首先二分
我们考虑建立最小割模型,则我们设源点
则对于每个点
对于每条边
注意double类型网络流中需注意精度问题
VI 2047. [ZOJ 2676]网络战争
首先题目条件是简单的,选择一些边,需要保证
我们要求
输出的是满足答案最小的方案数,即求最小割的方案数,我们只需在图上
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!