• 洛谷2494 [SDOI2011]保密 (分数规划+最小割)


    自闭一早上

    分数规划竟然还能被卡精度

    首先假设我们已经知道了到每个出入口的时间(代价)

    那我们应该怎么算最小的和呢?

    一个比较巧妙的想法是,由于题目规定的是二分图。

    我们不妨通过最小割的形式。
    表示这个基地必须从两个口之一进,从(S)连到奇数点,偶数点连到(T),流量是到这个点的时间。
    然后对于每个空腔的(u和v,(u->v,inf))表示这个二者至少要到一个。
    那么这样跑一遍最小割,就表示经过所有空腔的最小代价。
    那么现在其实问题就转化成了
    如果求到一个点的时间(a[i])

    观察题目中的柿子。
    (a[i]=frac{sum t}{sum s})
    哎!这个是不是可以直接分数规划啊。

    因为有无限的军队,所以每个点之间是可以单独处理的。

    首先我们先考虑对于任意一个点(x)

    不妨直接二分
    (mid>frac{sum t}{sum s})

    [sum t-sum s imes mid<0 ]

    如果我们将边权设为(t-mid*s)
    那么我们只需要判断到一个点的最短路是否是小于0,如果小于,那么(ans<mid),继续二分即可。

    那么我们对于每一个点都做一个这样的过程,(a[i])也就能求出来了啦

    qwq
    这有一个需要注意的地方,也是我做的时候看题解才用的一个剪枝。

    就是我们用(spfa)求最短路的时候,只要遇到了目标点,并且(dis<=0),直接(return)

    这样能大大加快你程序的速度。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<map>
    #include<set>
    #define mk make_pair
    #define ll long long
    #define db double
    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-'0';ch=getchar();}
      return x*f;
    }
    const int maxn = 1410;
    const int maxm = 1e6+1e2;
    const double inf = 1e12;
    const double eps = 1e-4 ;
    int point[maxn],nxt[maxm],to[maxm];
    db val[maxm];
    int cnt=1,n,m;
    int h[maxn];
    int x[maxm],y[maxm];
    double w[maxm],p[maxm];
    int s,t;
    int st;
    double dis[maxn],cost[maxm];
    int vis[maxn];
    void init()
    {
      cnt=1;
      memset(point,0,sizeof(point));
    } 
    void addedge(int x,int y,db w)
    {
        nxt[++cnt]=point[x];
        to[cnt]=y;
        point[x]=cnt;
        val[cnt]=w;
    }
    void add(int x,int y,double w)
    {
        //printf("%d %d %.2lf
    ",x,y,w);
        nxt[++cnt]=point[x];
        to[cnt]=y;
        cost[cnt]=w;
        point[x]=cnt;
    }
    void insert(int x,int y,db w)
    {
        //cout<<x<<" "<<y<<" "<<w<<endl; 
        addedge(x,y,w);
        addedge(y,x,0);
    }
    queue<int> q;
    void spfa(int s,int ed)
    {
        for (int i=1;i<=maxn-2;i++) dis[i]=inf;
        memset(vis,0,sizeof(vis));
        while (!q.empty()) q.pop();
        dis[s]=0;
        q.push(s);
        while (!q.empty())
        {
            int x = q.front();
            q.pop();
            vis[x]=0;
            for (int i=point[x];i;i=nxt[i])
            {
                int p = to[i];
                if (dis[p]>dis[x]+cost[i])
                {
                    dis[p]=dis[x]+cost[i];
                    if (p==ed && dis[p]<=-eps) return;
                    if (!vis[p])
                    {
                        q.push(p);
                        vis[p]=1;
                    }
                }
            } 
        }
    }
    bool bfs(int s)
    {
        memset(h,-1,sizeof(h));
        while (!q.empty()) q.pop();
        h[s]=0;
        q.push(s);
        while (!q.empty())
        {
            int x = q.front();
            q.pop();
            for (int i=point[x];i;i=nxt[i])
            {
                int p = to[i];
                if (h[p]==-1 && val[i]>0) 
                {
                    h[p]=h[x]+1;
                    q.push(p);
                }
            }
        }
        if (h[t]==-1) return false;
        return true;
    }
    db dfs(int x,db low)
    {
       if (x==t ||low==0) return low;
       db totflow=0;
       for (int i=point[x];i;i=nxt[i])
       {
       	  int p = to[i];
       	  if (val[i]>0 && h[p]==h[x]+1)
       	  {
       	  	 db tmp = dfs(p,min(low,val[i]));
       	  	 val[i]-=tmp;
       	  	 val[i^1]+=tmp;
       	  	 low-=tmp;
       	  	 totflow+=tmp;
       	  	 if (low==0) return totflow;
          }
       }
       if (low>0) h[x]=-1;
       return totflow;
    }
    db dinic()
    {
        db ans=0;
        while (bfs(s))
        {
            ans=ans+dfs(s,inf);
        }
        return ans;
    }
    
    double uu=0;
    bool check(double mid,int xx)
    {
        init();
        for (int i=1;i<=m;i++)
          add(x[i],y[i],w[i]-mid*p[i]);
        spfa(n,xx);
        return (dis[xx]<=-eps);
    }
    double solve(int x)
    {
        double l=0,r=2e9;
        double ans=inf;
        while (r-l>=1e-4)
        {
            double mid = (l+r)/2;
            if(check(mid,x)) r=mid,ans=mid;
            else l=mid;
        }
        return ans;
    }
    double a[maxn];
    signed main()
    {
      n=read(),m=read();
      for (int i=1;i<=m;i++) 
        scanf("%lld%lld%lf%lf",&x[i],&y[i],&w[i],&p[i]);
      int num1=read(),num2=read();
      init();
      s=maxn-10;
      t=s+1;
      for (int i=1;i<=num2;i++)
      {
      	 double pp = solve(i);
      	 a[i]=pp;
      }
      init();
      for (int i=1;i<=num2;i++)
      {
      	 if (i&1) insert(s,i,a[i]);
      	 else insert(i,t,a[i]);
      }
      for (int i=1;i<=num1;i++)
      {
      	 int u=read(),v=read();
      	 if (v&1) swap(u,v);
      	 if (a[u]==inf && a[v]==inf) 
      	 {
      	 	cout<<-1;
      	 	return 0;
         }
      	 insert(u,v,inf);
      }
      double ptx = dinic();
      printf("%.1lf
    ",ptx);
      return 0;
    }
    
    
  • 相关阅读:
    Java 单测 回滚
    Java四种线程池的使用
    git gc
    Git 常用命令
    JPA 批量新增
    SpringData JPA 排除 扫描 exclude-filter 不能使用解决
    开源许可证GPL、BSD、MIT、Mozilla、Apache和LGPL的区别
    深入浅出 RPC
    阿里 Java面试 知识点
    Eclipse Egit 安装
  • 原文地址:https://www.cnblogs.com/yimmortal/p/10186740.html
Copyright © 2020-2023  润新知