01分数规划的理解以及练习poj2976 poj 3621 poj 2728



              01 分数规划的思想的描述如下:令 c=(c1,c2,…,cn) d=(d1,d2,…,dn) n 维整数向量,那么一个 0-1 分数规划问题用公式描述如下 :FP:  最小化或者最大化 (c1x1+…cnxn)/(d1x1…dnxn)=cx/dx xi∈{0,1}。这个问题的解决已经有了成形的算法,但是网上的解释大多过难难以直接理解,大部分对于数学基础的要求是很高的。

            先说说这种思想能够解决哪些问题 1:裸的01分数规划pku2976适合刚刚学习的练手以及试模板 2:01分数规划与图形的结合比如说环的判断pku3621 比如最优比例生成树pku2728 解决的思想大致一样 关键是对结论的简要证明,加深理解,然后灵活的运用。

           下面谈谈解决01分数规划的方法以及结论

           首先,假设要c*x/d*x最大(x,c,d均指向量),假设最优解为 val,设置这样的子问题,z(L)=c*x-d*x*L 分配x向量使 z最大,那么可以知道 如果c*x-L*x*d<0 那么无论怎么分配x向量都无法满足L值即val必然小于L 同样 我们看大于0的情况 这个时候说明可以分配x使得目标解大于L那么val必然大于L,那么很显然 L=val的时候c*x-d*x*L=0,并且z的值具有单调性下面是证明    

             设L1,L2,且L1>L2
   z(L1) = max { c*x-L1*d*x } = c*x1-L1*d*x1(x1是使得其最大的向量)

   =>     z(l)是关于L的单调递减函数。

因此我们可以用二分或者迭代来解决

       这里只是简单的证明并没有很严格的证明 但是对于使用来讲已经足够。

      下面具体使用结论来解决上面的三道例子;

        pku2976   很直接的一道题 题意就是简单01分数规划

     来说说做法 由于题目已经告诉我们去掉K个x,我们要使得分数最高,设置子问题 z,根据上面的公式很容易写出程序。

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define iinf 2000000000
#define linf 1000000000000000000LL
#define dinf 1e200
#define eps 1e-6
#define all(v) (v).begin(),(v).end()
#define sz(x)  x.size()
#define pb push_back
#define mp make_pair
#define lng long long
#define sqr(a) ((a)*(a))
#define pii pair
#define pll pair
#define pss pair
#define pdd pair
#define X first
#define Y second
#define pi 3.14159265359
#define ff(i,xi,n) for(int i=xi;i<=(int)(n);++i)
#define ffd(i,xi,n) for(int i=xi;i>=(int)(n);--i)
#define ffl(i,r) for(int i=head[r];i!=-1;i=edge[i].next)
#define cc(i,j) memset(i,j,sizeof(i))
#define two(x)			((lng)1<<(x))
#define N 555555
#define M 1000000
#define lson l , mid , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
#define Mod  n
#define Pmod(x) (x%Mod+Mod)%Mod
using namespace std;
typedef vector  vi;
typedef vector  vs;
typedef unsigned int uint;
typedef unsigned lng ulng;
template inline void checkmax(T &x,T y)
{
    if(x inline void checkmin(T &x,T y)
{
    if(x>y) x=y;
}
template inline T Min(T x,T y)
{
    return (x>y?y:x);
}
template inline T Max(T x,T y)
{
    return (x T gcd(T a,T  b)
{
    return (a%b)==0?b:gcd(b,a%b);
}
template T lcm(T a,T b)
{
    return a*b/gcd(a,b);
}
template T Abs(T a)
{
    return a>0?a:(-a);
}
using namespace std;
struct node
{
    int x,y;
} a[1005];
double low,high,mid;
int cmp(node bb,node cc)
{
    return mid*bb.y-bb.x



pku3621 这道题是要求一个最大(边权和/点权和)的环 同样设置子问题 边权-点权*L最大的回路,如果存在并大于0 r=mid 可以直接用spfa的判环 将权编程负值然后判断有没有负环即可 


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define iinf 2000000000
#define linf 1000000000000000000LL
#define dinf 1e200
#define eps 1e-3
#define all(v) (v).begin(),(v).end()
#define sz(x)  x.size()
#define pb push_back
#define mp make_pair
#define lng long long
#define sqr(a) ((a)*(a))
#define pii pair
#define pll pair
#define pss pair
#define pdd pair
#define X first
#define Y second
#define pi 3.14159265359
#define ff(i,xi,n) for(int i=xi;i<=(int)(n);++i)
#define ffd(i,xi,n) for(int i=xi;i>=(int)(n);--i)
#define ffl(i,r) for(int i=head[r];i!=-1;i=edge[i].next)
#define cc(i,j) memset(i,j,sizeof(i))
#define two(x)			((lng)1<<(x))
#define N 1050
#define M 10000
#define lson l , mid , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
#define Mod  n
#define Pmod(x) (x%Mod+Mod)%Mod
using namespace std;
typedef vector  vi;
typedef vector  vs;
typedef unsigned int uint;
typedef unsigned lng ulng;
template inline void checkmax(T &x,T y){if(x inline void checkmin(T &x,T y){if(x>y) x=y;}
template inline T Min(T x,T y){return (x>y?y:x);}
template inline T Max(T x,T y){return (x T gcd(T a,T  b){return (a%b)==0?b:gcd(b,a%b);}
template T lcm(T a,T b){return a*b/gcd(a,b);}
template T Abs(T a){return a>0?a:(-a);}
struct pp
{
    int v,next,w;
}edge[M];
double  dist[N];
int f[N],head[N];
bool inque[N];
int cnt[N];
int n,m,tot;
double l,r,ans,mid;
inline void addedge(int u,int v,int w)
{
    edge[tot].v=v,edge[tot].w=w,edge[tot].next=head[u],head[u]=tot++;
}
bool spfa()
{
    queue q;
    ff(i,1,n) dist[i]=iinf;
    cc(cnt,0);
    cc(inque,0);
    q.push(1);
    inque[1]=1,cnt[1]=1;
    dist[1]=0;
    while(!q.empty())
    {
        int u=q.front();
        inque[u]=0;
        q.pop();
        ffl(i,u)
        {
            double w=edge[i].w;
            int v=edge[i].v;
            w=mid*w-f[v];
            if(dist[v]>dist[u]+w)
            {
                dist[v]=dist[u]+w;
                if(!inque[v])
                {
                    inque[v]=1;
                    q.push(v);
                    cnt[v]++;
                    if(cnt[v]>=n) return 1;
                }
            }
        }
    }
    return 0;
}
int main()
{
    while(scanf("%d%d",&n,&m)==2)
    {
        ff(i,1,n) scanf("%d",f+i);
        tot=0;
        cc(head,-1);
        ff(i,1,m)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
        }
        l=0,r=1996;
        while(r-l>=0.001)
        {
            mid=(l+r)/2;
            if(spfa())
            {
                l=mid;
                ans=mid;
            }
            else
            r=mid;
        }
        printf("%.2f\n",ans);
    }
    return 0;
}
pku2728

最优比例生成树

说白了就是求最小的(代价权和/边权和)的生成树问题 同样设置子问题 代价权-边权*L最小 即重新构造图 然后求最小生成树 同样如果 小于0 自己推导下就会知道 r=mid 另外poj会卡stl 裸奔的prim算法能过 优先队列优化的反而超时 


#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define iinf 2000000000
#define linf 1000000000000000000LL
#define dinf 1e200
#define eps 1e-5
#define all(v) (v).begin(),(v).end()
#define sz(x)  x.size()
#define pb push_back
#define mp make_pair
#define lng long long
#define sqr(a) ((a)*(a))
#define pii pair
#define pll pair
#define pss pair
#define pdd pair
#define X first
#define Y second
#define pi 3.14159265359
#define ff(i,xi,n) for(int i=xi;i<=(int)(n);++i)
#define ffd(i,xi,n) for(int i=xi;i>=(int)(n);--i)
#define ffl(i,r) for(int i=head[r];i!=-1;i=edge[i].next)
#define cc(i,j) memset(i,j,sizeof(i))
#define two(x)			((lng)1<<(x))
#define N 1050
#define M 1000000
#define lson l , mid , rt << 1
#define rson mid + 1 , r , rt << 1 | 1
#define Mod  n
#define Pmod(x) (x%Mod+Mod)%Mod
using namespace std;
typedef vector  vi;
typedef vector  vs;
typedef unsigned int uint;
typedef unsigned lng ulng;
template inline void checkmax(T &x,T y){if(x inline void checkmin(T &x,T y){if(x>y) x=y;}
template inline T Min(T x,T y){return (x>y?y:x);}
template inline T Max(T x,T y){return (x T gcd(T a,T  b){return (a%b)==0?b:gcd(b,a%b);}
template T lcm(T a,T b){return a*b/gcd(a,b);}
template T Abs(T a){return a>0?a:(-a);}
int n,h[N];
struct ps
{
    int x,y;
}cor[N];
inline double  Distance(ps &p, ps &q )
{
    return sqrt((double)sqr(p.x-q.x)+(double)sqr(p.y-q.y));
}
double l,r,ans,mid,dist[N];
double cost[N][N],len[N][N],ww[N][N];
inline void prim()
{
    ans=0;
    bool in[N]={};
    dist[1]=0;
    ff(i,2,n) dist[i]=iinf;
    ff(i,1,n)
    {
        double w=iinf;
        int id;
        ff(j,1,n)
        if(!in[j]&&dist[j]=eps)
       {
           mid=(l+r)/2;
              for(int i=1;i<=n;i++)
              for(int j=i+1;j<=n;j++)
                ww[i][j]=ww[j][i]=cost[i][j]-len[i][j]*mid;
           prim();
           if(ans<0) r=mid;
           else
            l=mid;
       }
       printf("%.3f\n",mid);
   }
    return 0;
}

这类问题的种类很少  基本属于模板题范畴 不如动态规划这些博大精深··· 01分数规划的理解以及练习poj2976 poj 3621 poj 2728_第1张图片


你可能感兴趣的:(distance,struct,c,算法,图形,编程,poj,数学)