[Example / summary] 0/1 fractional programming


I. Overview

0/1 score is planning to specifically address 0/1分数规划模型an algorithm(nonsense). So what 0/1 fractional programming model is it? Given integers { \ (A_1, A_2, A_3, ..., A_N \) }, { \ (B_1, B_2, B_3, ..., B_n \) } to choose the number of pairs, and that of their respective ratio of the maximum. Formula is as follows:
\ [\ FRAC {\ sum_. 1 = {P}} ^ {n-a_p \ Times x_p} {\ sum_. 1 = {P}} ^ {n-b_p \} x_p Times (x_p = 1,0) \]

Second, the realization principle

So what can we find such a seemingly very complex persimmon it? The correct answer is dichotomy, but for now the formula for solving the maximum value has nothing to do with the dichotomy.
We can guess any of a ratio \ (Q \) , this time to discuss two cases:

  1. \ (\ EXISTS \) { \ (x_1, x_2, ..., x_n \) }, so that \ (\ frac {\ sum_ { p = 1} ^ {n} a_p \ times x_p} {\ sum_ {p = 1} ^ {n} b_p \
    times x_p} (x_p = 1,0) \ geqslant Q \) by calculation found that solutions of greater than answer \ (Q \) , indicating that this time we \ (Q \) guess small a, \ (Q \) can continue to become larger.

  2. \ (\ FORALL \) { \ (x_1, x_2, ..., x_n \) }, so that \ (\ frac {\ sum_ { p = 1} ^ {n} a_p \ times x_p} {\ sum_ {p = 1} ^ {n} b_p \
    times x_p} (x_p = 1,0) \ lt Q \) all answers than \ (Q \) is small, we can draw \ (Q \) enumeration large the need to reduce.

The solver \ (Q \) process is not very familiar with? Wit you will find \ (Q \) has a dichotomy, this dichotomy and answer method is the same, so far we can use half the answer to solve this problem.

So how do you calculate whether there is such a ratio greater than we enumerate \ (Q \) it? Clearly, the direct calculation of this ratio is extremely unwise choice. At this point we need to be a little deformation on the formula.
This observation equation:
\ [\ FRAC {\ sum_. 1 = {P}} ^ {n-a_p \ Times x_p} {\ sum_. 1 = {P}} ^ {n-b_p \} x_p Times (x_p = 1,0) \ geqslant Q \]
we have to take the denominator of the right side of the equation:
\ [\ sum_. 1 = {P}} ^ {n-a_p \ Times x_p \ geqslant \ sum_. 1 = {P}} ^ {n-Q \ Times b_p \ Times x_p \]
in the persimmon to the left to the right:
\ [\ sum_. 1 = {P}} ^ {n-a_p \ Times x_p - \ sum_. 1 = {P}} ^ {n-Q \ Times b_p \ Times x_p \ geqslant 0 \]
extract common factor to obtain the final equation:
\ [\ sum_. 1 = {P}} ^ {n-(a_p-Q \ Times b_p) \ Times x_p \ geqslant 0 \]

Now that we know how to do, because there is a set of solutions as long as you can, so long as we find the maximum value of this formula and determine whether the value is greater than zero. Description is greater than 0 \ (Q \) is not big enough, less than 0 Description \ (Q \) is too big, with a dichotomy closer and closer to the answer until it reaches the proper accuracy.

Third, examples

The following example is not very difficult, place is a little complicated dichotomy check( )writing function.

Example. 1: POJ2976 Dropping Tests (formerly POJ2519)

Crazy topic EXPRESS allows you to use 01 scores planning. Binary enumeration results obtained value of each item and sorting (maximum requirement), then left to change the interval if the answer is less than 0, otherwise the right to change the interval.
Code:

#include<bits/stdc++.h>
#define N 2000
using namespace std;
int n,k;
double a[N],b[N],f[N];
double check(double mid)
{
    memset(f,0,sizeof(f));
    for(int i=1;i<=n;i++)
        f[i]=a[i]-mid*b[i];//转化后的公式
    sort(f+1,f+n+1,greater<double>());
    double sum=0;
    for(int i=1;i<=n-k;i++)
        sum+=f[i];//求一下最大值
    return (sum>0)? 1:0;
}
int main()
{
    while(scanf("%d%d",&n,&k)&&n+k)
    {
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        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=1e10;
        while(r-l>1e-8){
            double mid=(l+r)/2;
            if(check(mid)) l=mid;
            else r=mid;
        }
        cout<<fixed<<setprecision(0)<<l*100<<endl;
    }
    return 0;
}

Example 2: page P1730 path minimum density

All points to 01 points once planned, the next shortest run to determine the density of the enumeration is feasible, ultimate minimum density obtained path.

#include<bits/stdc++.h>
#define N 10010
#define INF 0x3f3f3f3f
#define eps 1e-6
#define ll long long
using namespace std;
double ans[N][N],dist[N],maxn,cost[N];
int q,n,m,tot,vis[N];
int first[N],go[N],next[N];
inline void add_edge(int u,int v,double w){
    next[++tot]=first[u];
    first[u]=tot;
    go[tot]=v;
    cost[tot]=w;
}
inline int check(int s,int ed,double mid){
    queue<int> q;
    for(int i=1;i<=n;i++){
        dist[i]=INF;vis[i]=0;
    }
    q.push(s);vis[s]=1;dist[s]=0;
    while(!q.empty()){
        int u=q.front();
        q.pop();vis[u]=0;
        for(int e=first[u];e;e=next[e]){
            int v=go[e];double w=cost[e];
            if(dist[v]>dist[u]+w-mid){
                dist[v]=dist[u]+w-mid;
                if(!vis[v]){
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
    }
    return (dist[ed]>0)? 1:0;//求的最小比值大于枚举值,更新l,否则更新r
}
inline void erfen(){
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++){
            if(i==j) continue;
            check(i,j,0);
            if(dist[j]==INF){ans[i][j]=-1;continue;}
            long double l=0,r=maxn;
            while(r-l>eps){
                long double mid=(l+r)/(2.0);
                if(!check(i,j,mid)) r=mid;
                else l=mid;
            }
            ans[i][j]=l;
        }
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1,u,v,w;i<=m;i++){
        scanf("%d%d%d",&u,&v,&w);
        add_edge(u,v,(double)w);
        maxn+=w;
    }
    erfen(); 
    scanf("%d",&q);
    for(int i=1,u,v;i<=q;i++){
        scanf("%d%d",&u,&v);
        ans[u][v]<0?printf("OMG!\n"):printf("%.3lf\n",ans[u][v]);
    }
    return 0;
}

Example 3: CF489E Hiking

Basic questions.
Code:

#include<bits/stdc++.h>
#define N 100010
using namespace std;
const double INF=1e15;
int n,last[N];
double len,pos[N],w[N],f[N];
vector<int> v;
double check(double mid)
{
    for(int i=1;i<=n;i++){
        f[i]=INF;
        for(int j=0;j<i;j++){
            if(f[i]>f[j]+sqrt(fabs(pos[i]-pos[j]-len))-mid*w[i]){
                f[i]=f[j]+sqrt(fabs(pos[i]-pos[j]-len))-mid*w[i];
                last[i]=j;
            }
        }
    }
    return (f[n]<=0)?1:0;
}
int main()
{
    scanf("%d%lf",&n,&len);
    for(int i=1;i<=n;i++)
        scanf("%lf%lf",&pos[i],&w[i]);
    double l=0,r=1e10;
    while(r-l>=1e-9){
        double mid=(l+r)/2;
        if(check(mid)) r=mid;
        else l=mid;
    }
    check(l);
    int now=n;
    while(now>0){
        v.push_back(now);
        now=last[now];
    }
    for(int i=v.size()-1;i>=0;i--)
        printf("%d ",v[i]);
    return 0;
}

Example. 4: P2868 [USACO07DEC] Things Sightseeing Cows Cow

This problem with the P1768 Pilgrim similar.
The cows eventually have to return to the starting point, we also enumerate a ratio \ (Q \) , you can know if the deformation inequality is greater than 0, that is present in the ring, then the update interval left endpoint \ (L \) . Analyzing one ring can be converted into a negative loop processing, i.e. with SPFA forfeit ring.

#include<bits/stdc++.h> 
#define N 200010
using namespace std;
int first[N],next[N],go[N],cost[N],vis[N];
int m,n,tot;
double dist[N],len[N],f[N];
inline void add_edge(int u,int v,int w){
    next[++tot]=first[u];
    first[u]=tot;
    go[tot]=v;
    cost[tot]=w;
}
double SPFA(int u)//判负环
{
    vis[u]=1;
    for(int i=first[u];i;i=next[i])
    {
        int v=go[i];
        double w=len[i];
        if(dist[v]>dist[u]+w)
        {
            dist[v]=dist[u]+w;
            if(vis[v]||SPFA(v)){
                vis[v]=0;
                return 1;
            }
        }
    }
    vis[u]=0;
    return 0;
}
double check(double mid)
{
    for(int i=1;i<=tot;i++)
        len[i]=(double)cost[i]*mid-f[go[i]];
    for(int i=1;i<=n;i++){
        if(SPFA(i)) return 1;
    }
    return 0;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%lf",&f[i]);
    for(int i=1;i<=m;i++){
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);
        add_edge(u,v,w);
    }
    double l=0,r=1e6;
    while(r-l>1e-6){
        double mid=(l+r)/2;
        if(check(mid))
            l=mid;
        else r=mid;
    }
    cout<<fixed<<setprecision(2)<<l<<endl;
    return 0;
}

Guess you like

Origin www.cnblogs.com/cyanigence-oi/p/11766432.html