01分数规划与最优比率环,最优比率生成树

1.luogu 4322 最佳团体,01分数规划+树形dp

#include<bits/stdc++.h> 
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define fill(x,t) memset(x,t,sizeof(x))

const double EPS=1e-4;
const int N=2505;
const int E=5005;
using namespace std;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}
double f[N][N],tmp[N],v[N];
int siz[N],a[N],b[N],head[N],tot;
struct node{int u,v,next;}e[E];
void insert(int u,int v) {
    e[++tot]=(node){u,v,head[u]};head[u]=tot;
    e[++tot]=(node){v,u,head[v]};head[v]=tot;}

void dfs(int u,int fa) {
    siz[u]=1;f[u][0]=0;f[u][1]=v[u];
    for (int i=head[u];i;i=e[i].next){
        int v=e[i].v;
        if(v==fa) continue;
        dfs(v,u);
        rep(j,1,siz[u]+siz[v]) tmp[j]=f[0][N-1];
        rep(j,1,siz[u])rep(k,0,siz[v])
            tmp[j+k]=max(tmp[j+k],f[u][j]+f[v][k]);
        siz[u]+=siz[v];
        rep(j,1,siz[u]) f[u][j]=tmp[j];
    }
}
int main(){
    int n,m; scanf("%d%d",&m,&n);
    rep(i,1,n){
        int fa;scanf("%d%d%d",&b[i],&a[i],&fa);
        insert(fa,i);}
    double l,r;
    for (l=0,r=10000;r-l>=EPS;) {
        double mid=(l+r)*0.5;
        fill(f,0xc2);
        rep(i,1,n) v[i]=(double)a[i]-mid*(double)b[i];
        dfs(0,0);
        if(f[0][m+1]>0) l=mid;
        else r=mid;}
    printf("%.3lf\n", l);return 0;
}

2.最优比率环

luogu 2868 n点m有向边,点上权值为a,边上权值b求   sigma(a[i])/sigma(b[i]) 最大

仿照01分数规划模型

想到二分一个mid判定图上是否存在一个环s

上式子可转化为 sigma (a[i]-mid*b[i])>0 ,a,b分别对应点集和边集

因为实际作上式子十分麻烦

故判定 sigma (mid*b[i]-a[i])<0 判断图中是否存在负环,利用dfs的spfa(快)

bfs版本

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define dec(i,x,y) for(register int i=x;i>=y;i--)
#define ll long long
using namespace std;
const int N=1010;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}
double dis[N];int n,m,a[N];
int head[N],tot;int vis[N],num[N];
struct node{int v,w,next;}e[5010];
void insert(int u,int v,int w){
    e[++tot]=(node){v,w,head[u]};head[u]=tot;}

bool check(double k){
    queue<int> q;
    rep(i,1,n){q.push(i);dis[i]=0;vis[i]=num[i]=1;}
    while(!q.empty()){
        int u=q.front();
        q.pop();vis[u]=0;
        for(int i=head[u];i;i=e[i].next){
            int v=e[i].v;double w=e[i].w;
            if(dis[v]>dis[u]+k*w-(double)a[u]){
                dis[v]=dis[u]+k*w-(double)a[u];
                if(!vis[v]){
                    q.push(v);vis[v]=1;
                    if(++num[v]>=n) return 1;
                }
            }
        }
    }
    return 0;
}
int main(){
    n=read(),m=read();
    rep(i,1,n) a[i]=read();
    rep(i,1,m){
    int u=read(),v=read(),w=read();insert(u,v,w);}
    double l=0,r=1000010,mid;
    while(r-l>1e-6){
        double mid=(l+r)/2.0;
        if(check(mid)) l=mid;else r=mid;}
    printf("%.2lf\n",l);return 0;
}

dfs版

#include<bits/stdc++.h>
#define rep(i,x,y) for(register int i=x;i<=y;i++)
#define dec(i,x,y) for(register int i=x;i>=y;i--)
#define ll long long
using namespace std;
const int N=51000;
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    return x*f;}
bool vis[N];int n,m,x,y,z,tot;
int a[N],num[N],head[N];
double ans,mid,l,r,w[N],dis[N];
struct node{int v,w,next;}e[N];
void insert(int u,int v,int w){
    e[++tot]=(node){v,w,head[u]};head[u]=tot;}
int spfa(int u){
    vis[u]=1;
    for(int i=head[u];i;i=e[i].next){
        int v=e[i].v;
        if(dis[v]>dis[u]+w[i]){
            dis[v]=dis[u]+w[i];
            if(vis[v]||spfa(v)){
                vis[u]=0;
                return 1;
            } 
        }
    }
    vis[u]=0;
    return 0;
}
bool check(){
    rep(i,1,n) if(spfa(i)) return 1;return 0;
}
int main(){
    n=read(),m=read();
    rep(i,1,n) a[i]=read();
    rep(i,1,m){
    int x=read(),y=read(),z=read();insert(x,y,z);}
    l=0,r=100005;
    while(r-l>1e-7){
        mid=(l+r)/2.0;
        rep(i,1,tot){
            int v=e[i].v;
            w[i]=(double)mid*e[i].w-a[v];
        }
        if(check()) l=mid;else r=mid;
    }
    printf("%.2lf\n",l);return 0;
}

3.最优比率生成树

日后填坑

posted @ 2018-09-04 13:17  ASDIC减除  阅读(234)  评论(0编辑  收藏  举报