0/1分数规划专题
概念及解法
推荐博客:https://blog.csdn.net/niiick/article/details/80925267
例题
T1 POJ 2976 Dropping Tests
题解
分数规划裸题
因为要去掉k场考试,因此直接排个序,看最大的前n-k组的和是否大于0即可
代码
#include <cmath>
#include <cstdio>
#include <climits>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define M 1009
using namespace std;
int a[M],b[M],n,k;
const double eps=1e-4;
double A[M];
int read(){
char ch;
int f=1,re=0;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1;ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
bool check(double mid){
double ans=0;
for(int i=1;i<=n;i++) A[i]=a[i]-mid*b[i];
sort(A+1,A+n+1);
for(int i=k+1;i<=n;i++) ans+=A[i];
return ans>=0;
}
int main(){
while(scanf("%d%d",&n,&k)!=EOF){
if(n==0&&k==0) return 0;
for(int i=1;i<=n;i++) a[i]=read();
for(int i=1;i<=n;i++) b[i]=read();
double l=0,r=1;
while(r-l>=eps){
double mid=(l+r)/2.0;
if(check(mid)) l=mid;
else r=mid;
}printf("%.0lf\n",100*l);
}return 0;
}
T2 最小密度路径
题解
最短路+分数规划
代码
#include<bits/stdc++.h>
#define M 200009
using namespace std;
const int inf=1e9+7;
const double eps=1e-7;
double d[M],ans[59][59];
int n,m,q,nxt[M],w[M],to[M],first[M],tot,maxn;
bool vis[M];
int read(){
char ch;
int f=1,re=0;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1;ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
void add(int x,int y,int z){
nxt[++tot]=first[x];
first[x]=tot;
w[tot]=z;
to[tot]=y;
}
bool check(int x,int y,double mid){
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++) d[i]=inf;
d[x]=0,vis[x]=1;
queue<int>q;
q.push(x);
while(q.size()){
int u=q.front();
q.pop(),vis[u]=0;
for(int i=first[u];i;i=nxt[i]){
int v=to[i];
if(d[v]>d[u]+w[i]-mid){
d[v]=d[u]+w[i]-mid;
if(!vis[v]) q.push(v),vis[v]=1;
}
}
}return d[y]>=0;
}
void getans(int x,int y){
double l=0,r=maxn;
check(x,y,0);
if(d[y]==inf){
ans[x][y]=-1;
return;
}
while(r-l>eps){
double mid=(l+r)/2;
if(check(x,y,mid)) l=mid;
else r=mid;
}ans[x][y]=l;
}
int main(){
int x,y,z;
n=read(),m=read();
for(int i=1;i<=m;i++){
x=read(),y=read(),z=read();
add(x,y,z),maxn+=z;
}q=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) getans(i,j);
for(int i=1;i<=q;i++){
x=read(),y=read();
if(ans[x][y]==-1) printf("OMG!\n");
else printf("%.3lf\n",ans[x][y]);
}return 0;
}
T3 Talent Show
题解
背包dp+分数规划
代码实现
#include<bits/stdc++.h>
#define int long long
#define M 200000
using namespace std;
int read(){
char ch;
int f=1,re=0;
for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
if(ch=='-'){f=-1;ch=getchar();}
for(;isdigit(ch);ch=getchar()) re=(re<<3)+(re<<1)+ch-'0';
return re*f;
}
const double eps=1e-7;
const int inf=1e9+7;
double f[M];
int n,m,w,a[M],b[M];
bool check(double mid){
for(int i=1;i<=m;i++) f[i]=-inf;
for(int i=1;i<=n;i++)
for(int j=m;j>=0;j--){
if(f[j]==-inf) continue;
int k=j+b[i];k=min(k,m);
f[k]=max(f[k],f[j]+a[i]-b[i]*mid);
}return f[m]>=0;
}
signed main(){
n=read(),m=read();
for(int i=1;i<=n;i++) b[i]=read(),a[i]=read();
double l=0,r=250001;
while(r-l>=eps){
double mid=(l+r)/2;
if(check(mid)) l=mid;
else r=mid;
}printf("%lld\n",(int)(l*1000));
return 0;
}