现在的位置: 首页 > 算法 > 正文

zoj 3691 二分+最大流

2019年02月27日 算法 ⁄ 共 1786字 ⁄ 字号 评论关闭

传送门

其他不讲,就说说建图吧,下面以3个点为例:

我用的算法效率不高,想更快的可以用dinic或sap

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
int n,en;
int f[41111];
int fst[333],next[41111],node[41111],c[41111],lu[333],pre[333];
double l[41111];
double x[333],y[333],z[333];
int jj[333],cc[333];
bool vis[333];
int q[33333];
int af;
void init()
{
    af=0;
    en=0;
    memset(fst,-1,sizeof(fst));
}
void add(int u,int v,double d,int cnt)
{
    //cout<<u<<" "<<v<<" "<<d<<" "<<cnt<<endl;
    next[en]=fst[u];
    fst[u]=en;
    node[en]=v;
    l[en]=d;
    c[en]=cnt;
    en++;
}
double dis(int i,int j)
{
    return sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j])+(z[i]-z[j])*(z[i]-z[j]));
}
void build()
{
    for(int i=1; i<=n; i++)
    {
        add(0,i,0,jj[i]);
        add(i,0,0,0);
    }
    for(int i=2; i<=n; i++)
    {
        for(int j=2; j<=n; j++)
        {
            double d=dis(i,j);
            if(i==j)
            {
                add(i,n+j,d,cc[i]);
                add(n+j,i,d,0);
            }
            else
            {
                add(n+j,i,d,cc[j]);
                add(i,n+j,d,0);
            }
        }
    }
    for(int i=2; i<=n; i++)
    {
        double d=dis(1,i);
        add(n+i,1,d,cc[i]);
        add(1,n+i,d,0);
    }
}
bool bfs(int s,int t,double d)
{
    memset(vis,0,sizeof(vis));
    int fn=0,ed=0;
    q[ed++]=0;
    vis[0]=1;
    while(fn<ed)
    {
        int u=q[fn++];
        for(int i=fst[u]; i!=-1; i=next[i])
        {
            if(d-l[i]<1e-9)continue;
            int v=node[i];
            if(c[i]-f[i]>0&&!vis[v])
            {
                pre[v]=u;
                lu[v]=i;
                if(v==t)return true;
                q[ed++]=v;
                vis[v]=1;
            }
        }
    }
    return false;
}
int ek(int s,int t,double d)
{
    int ans=0;
    memset(f,0,sizeof(f));
    while(bfs(s,t,d))
    {
        int mm=af;
        for(int i=t; i!=s; i=pre[i])
        {
            int v=lu[i];
            if(mm>c[v]-f[v])mm=c[v]-f[v];
        }
        for(int i=t; i!=s; i=pre[i])
        {
            int v=lu[i];
            f[v]+=mm;
            f[v^1]-=mm;
        }
        ans+=mm;
    }
    return ans;
}
void solve()
{
    double low=0,high=40000,mid;
    while(high-low>1e-9)
    {
        mid=(high+low)/2.0;
        if(ek(0,1,mid)==af)high=mid;
        else low=mid;
    }
    if(low>39999)cout<<-1<<endl;
    else printf("%.7f\n",low);
}
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        init();
        bool fff=0;
        for(int i=1; i<=n; i++)
        {
            scanf("%lf%lf%lf%d%d",&x[i],&y[i],&z[i],&jj[i],&cc[i]);
            af+=jj[i];
            if(jj[i]>cc[i]&&i!=1)fff=1;
        }
        if(fff)
        {
            cout<<-1<<endl;
            continue;
        }
        build();
        solve();
    }
    return 0;
}
【上篇】
【下篇】

抱歉!评论已关闭.