【分数规划】

烂漫一生 提交于 2019-11-27 10:22:07

分数规划

资料

这样一类问题,给定两个数组,benifit[i]表示选取i的收益,cost[i]表示选取i的代价。如果选取i,定义x[i]=1否则x[i]=0。每一个物品只有选或者不选两种方案,求一个选择方案使得\(R=\sum(benifit[i]*x[i])/\sum(cost[i]*x[i])\)取得最值,即所有选择物品的总收益与总代价的比值最大或是最小

实战

POJ2976Dropping tests 普通01分数规划

题意:给出n个a和b,让选出n-k个使得\((\sum a[i])/(\sum b[i])\)最大
普通分数规划 就是因为是实数要注意一些小细节

二分
#define ll long long #define Abs(x) ((x)(y)?(x):(y)) #define Min(x,y) ((x)
#include<cstdio> #include<iostream> #include<cmath> #include<algorithm> #include<cstring>  using namespace std; #define ll long long #define Abs(x) ((x)<0?-(x):(x)) const int N=1000+5,M=5e5+5,INF=1e9+7,inf=0x3f3f3f3f; const double eps=1e-7; int n,k; double a[N],b[N],d[N]; template <class t>void rd(t &x){     x=0;int w=0;char ch=0;     while(!isdigit(ch)) w|=ch=='-',ch=getchar();     while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();     x=w?-x:x; }  double check(double l){     double sum=0.0;     for(int i=1;i<=n;++i) d[i]=a[i]-l*b[i];     sort(d+1,d+n+1);     for(int i=k+1;i<=n;++i) sum+=d[i];     return sum; }  int main(){     while(scanf("%d%d",&n,&k)!=EOF&&n+k){         double l=0.0,r=0.0,mid;         for(int i=1;i<=n;++i) scanf("%lf",&a[i]);         for(int i=1;i<=n;++i){             scanf("%lf",&b[i]);             if(a[i]/b[i]>r) r=a[i]/b[i];         }         while(r-l>eps){             mid=(l+r)/2;             if(check(mid)>0) l=mid;             else r=mid;         }         printf("%.0f\n",l*100);     }     return 0; }

POJ2728Desert King 最优比率生成树

有n个点,每个点有一个坐标和高度
两点之间的费用是高度之差的绝对值 两点之间的距离就是欧几里得距离
求一棵生成数,使得单位距离的费用最小

即求得花费/收益比值最小

(开始没懂...原来是没好好读题)

#include<iostream> #include<cstdio> #include<queue> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define ll long long #define Abs(x) ((x)<0?-(x):(x)) #define Max(x,y) ((x)>(y)?(x):(y)) #define Min(x,y) ((x)<(y)?(x):(y)) const int N=1000+5,M=5e5+5,INF=1e9+7,inf=0x3f3f3f3f; const double eps=1e-7; int n,k; double a[N][N],b[N][N]; template <class t>void rd(t &x){     x=0;int w=0;char ch=0;     while(!isdigit(ch)) w|=ch=='-',ch=getchar();     while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();     x=w?-x:x; }  struct node{int x,y,h;}nd[N]; double qdis(int i,int j){return sqrt(1.0*(nd[i].x-nd[j].x)*(nd[i].x-nd[j].x)+1.0*(nd[i].y-nd[j].y)*(nd[i].y-nd[j].y));}  bool vis[N]; double dis[N],d[N][N]; double prim(double x){     double sum=0.0;     for(int i=0;i<=n;++i) dis[i]=1e20,d[i][i]=0.0,vis[i]=0;     dis[1]=0.0;     for(int i=1;i<=n;++i)     for(int j=i+1;j<=n;++j)     d[i][j]=d[j][i]=b[i][j]-x*a[i][j];     for(int i=1,u=0;i<=n;++i,u=0){         for(int j=1;j<=n;++j)         if(!vis[j]&&dis[j]<dis[u]) u=j;         vis[u]=1,sum+=dis[u];         for(int v=1;v<=n;++v)         if(!vis[v]) dis[v]=Min(dis[v],d[u][v]);     }     return sum; }  int main(){     freopen("in.txt","r",stdin);     while(scanf("%d",&n)!=EOF&&n){         double l=0.0,r=0.0,mid;         for(int i=1;i<=n;++i) rd(nd[i].x),rd(nd[i].y),rd(nd[i].h);         for(int i=1;i<=n;++i)         for(int j=i+1;j<=n;++j)         a[i][j]=a[j][i]=qdis(i,j),b[i][j]=b[j][i]=1.0*Abs(nd[i].h-nd[j].h),r=Max(r,b[i][j]/a[i][j]);         while(r-l>=eps){             mid=(l+r)/2;             if(prim(mid)>0) l=mid;             else r=mid;         }         printf("%.3f\n",l);     }     return 0; }

USACOSightseeing Cows 最优比率环

在有向图图中选出一个环,使得这个环的点权/边权最大

即在每次check的时候找一个正环 可是正环并不好找 就将边权改为负值去找负环

打了一个下午超级悲伤 不知道哪里错了一直给我报错 然后怒而全部删掉重打 然后一遍过... 一言难尽
#include<iostream> #include<cstdio> #include<queue> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define ll long long #define Abs(x) ((x)<0?-(x):(x)) #define Max(x,y) ((x)>(y)?(x):(y)) #define Min(x,y) ((x)<(y)?(x):(y)) const int N=1000+5,M=5000+5,INF=1e9+7,inf=0x3f3f3f3f; const double eps=1e-7; int n,m,a[N],fr[M],to[M],co[M]; template <class t>void rd(t &x){     x=0;int w=0;char ch=0;     while(!isdigit(ch)) w|=ch=='-',ch=getchar();     while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();     x=w?-x:x; }  int head[N],tot; struct edge{int v,nxt;double w;}e[M]; void add(int u,int v,double w){     e[++tot]=(edge){v,head[u],w},head[u]=tot; }  bool vis[N];double dis[N]; int cnt[N]; queue<int>q; bool spfa(){     while(!q.empty()) q.pop();     for(int i=1;i<=n;++i) dis[i]=0.0,cnt[i]=vis[i]=1,q.push(i);//图有可能不连通     while(!q.empty()){         int u=q.front();         q.pop(),vis[u]=0;         for(int i=head[u],v;i;i=e[i].nxt){             v=e[i].v;             if(dis[v]>dis[u]+e[i].w){                 dis[v]=dis[u]+e[i].w;                 if(!vis[v]) q.push(v),vis[v]=1,++cnt[v];                 if(cnt[v]>=n) return 1;             }         }     }     return 0; } bool check(double x){     memset(head,0,sizeof(head)),tot=0;     for(int i=1;i<=m;++i) add(fr[i],to[i],-((double)a[to[i]]-x*co[i]));     if(spfa()) return 1;//找到负环     else return 0; }   int main(){     freopen("in.txt","r",stdin);     rd(n),rd(m);     for(int i=1;i<=n;++i) rd(a[i]);     for(int i=1;i<=m;++i) rd(fr[i]),rd(to[i]),rd(co[i]);     double l=0.0,r=3000.0,mid;     while(r-l>=eps){         mid=(l+r)/2;         if(check(mid)) l=mid;         else r=mid;     }     printf("%.2f",l);     return 0; }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!