zoukankan      html  css  js  c++  java
  • 【SCOI2014】方伯伯运椰子

    题面

    https://loj.ac/problem/2214

    一道好题。

    最小费用最大流+调整法($orz$杨颙)(原谅我想到杨颙,好像我们好久没见了)

    先假设所有的路都被压缩至$w=0$,然后建两类边,用最小费用最大流扩大(类似的思想:棋盘占领)。

    注意求出的东西应该是后来的费用$Y - $之前的费用$X + k imes mid$,所以$check()$的时候要取反(这个地方我想了好久。。。。。)

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<vector>
    #include<queue>
    #include<cmath>
    #define ri register int
    #define N 5050
    #define M 3050
    #define INF 1000000007
    #define LL long long
    #define T (n+2)
    #define S (n+1)
    
    using namespace std;
    
    int n,m;
    int u[M],v[M],a[M],b[M],c[M],d[M];
    
    struct graph {
      vector<int> to,w,ed[N];
      vector<double> c;
      double dis[N]; int cur[N]; bool vis[N];
      void clear() {
        c.clear(); to.clear(); w.clear();
        for (ri i=1;i<=n+2;i++) ed[i].clear();
      }
      void add_edge(int a,int b,int aw,double ac) {
        to.push_back(b); w.push_back(aw); c.push_back(ac);  ed[a].push_back(to.size()-1);
        to.push_back(a); w.push_back(0);  c.push_back(-ac); ed[b].push_back(to.size()-1);
      }
      bool spfa() {
        for (ri i=1;i<=n+2;i++) dis[i]=100000000000000.7;
        memset(vis,0,sizeof(vis));
        queue<int> q;
        dis[S]=0;q.push(S);vis[S]=1;
        while (!q.empty()) {
          int x=q.front(); q.pop();
          for (ri i=0;i<ed[x].size();i++) {
            int e=ed[x][i];
            if (dis[to[e]]>dis[x]+c[e] && w[e]) {
              dis[to[e]]=dis[x]+c[e];
              if (!vis[to[e]]) vis[to[e]]=1,q.push(to[e]);
            }
          }
          vis[x]=0;
        }
        return dis[T]<100000000000000.7;
      }
      int dfs(int x,int lim) {
        if (x==T || !lim) return lim;
        LL sum=0; vis[x]=1;
        for (ri &i=cur[x];i<ed[x].size();i++) {
          int e=ed[x][i];
          if (fabs(dis[x]+c[e]-dis[to[e]])<1e-5 && w[e] && !vis[to[e]]) {
            int f=dfs(to[e],min(lim,w[e]));
            w[e]-=f; w[1^e]+=f;
            lim-=f; sum+=f;
            if (!lim) return sum;
          }
        }
        return sum;
      }
      double zkw() {
        double ret=0;
        while (spfa()) {
          memset(vis,0,sizeof(vis));
          memset(cur,0,sizeof(cur));
          ret+=dfs(S,INF)*dis[T];
        }
        return ret;
      }
    } G;
    
    bool can(double mid) {
      double dec=0;
      for (ri i=1;i<=m;i++) dec+=(a[i]-d[i]+mid)*c[i];
      for (ri i=1;i<=m;i++) {
        G.add_edge(u[i],v[i],c[i],-(a[i]+mid-d[i]));
        if (u[i]!=S) G.add_edge(u[i],v[i],INF,b[i]+mid+d[i]);
      }
      if (0-(dec+G.zkw())>0) return 1; else return 0;
    }
    
    int main() {
      scanf("%d %d",&n,&m);
      for (ri i=1;i<=m;i++) {
        scanf("%d %d %d %d %d %d",&u[i],&v[i],&a[i],&b[i],&c[i],&d[i]);
      }
      double lb=0,rb=50000.0;
      double ans=0;
      while (rb-lb>1e-3) {
        double mid=(lb+rb)/2;
        //printf("%.5lf %.5lf %.5lf
    ",lb,rb,mid);
        G.clear();
        if (can(mid)) lb=ans=mid; else rb=mid;
      }
      printf("%.2lf
    ",ans);
      return 0;
    }
  • 相关阅读:
    php配置GD库
    Linux 安装 Apache2+php5+gd+freetype2
    gd库
    数组和链表的区别
    python 整数中1出现的次数
    python栈--字符串反转,括号匹配
    Linux基础知识
    操作系统
    后台面试问题
    python 面向对象
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11272076.html
Copyright © 2011-2022 走看看