P2402 奶牛隐藏二分最大流

Posted orangeko

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2402 奶牛隐藏二分最大流相关的知识,希望对你有一定的参考价值。

题目背景

这本是一个非常简单的问题,然而奶牛们由于下雨已经非常混乱,无法完成这一计算,于是这个任务就交给了你。(奶牛混乱的原因看题目描述)

题目描述

在一个农场里有 nn 块田地。某天下午,有一群牛在田地里吃草,他们分散在农场的诸多田地上,农场由 mm 条无向的路连接,每条路有不同的长度。

突然,天降大雨,奶牛们非常混乱,想要快点去躲雨。已知每个田地都建立有一个牛棚,但是每个牛棚只能容纳一定数量的牛躲雨,如果超过这个数量,那多出的牛只能去别的田地躲雨。奶牛们每移动 11 的距离花费 11 时间,奶牛们想知道它们全部都躲进牛棚,最少需要多少时间。(即最后一头奶牛最少要花多久才能躲进牛棚)。

输入格式

第一行有两个整数,分别代表田地数 nn 和道路数 mm。

接下来 nn 行,每行两个整数,第 (i + 1)(i+1) 行的整数 s_i, p_isi?,pi? 分别表示第 ii 块田地的牛的数量以及该田地的牛棚最多可以容纳多少牛。

接下来 mm 行,每行三个整数 u, v, wu,v,w,代表存在一条长度为 ww 的连接 uu 和 vv 的道路。

输出格式

输出一行一个整数表示所有奶牛全都躲进牛棚所用的最少时间。如果无法使全部奶牛都躲进牛棚,输出 -11。

输入输出样例

输入 #1
3 4 
7 2 
0 4 
2 6 
1 2 40 
3 2 70 
2 3 90 
1 3 120
输出 #1
110
技术图片

 

 

思路

  这道题和之前EOJ月赛上的一道题差不多。

  建图很好想。

  对每个 i 点拆开,入点装过路牛,连向S。

  出点装雨棚里能待的牛,连向T。

  出入点之间的容量显然为雨棚的容量。

  用 Floyd 预处理出每个雨棚之间的距离

  二分枚举牛进雨棚的时间

  以此作为限制条件建图

  通过限定连边的长度来限制时间

  当恰好流量等于牛的数量时,

  说明此时所有牛能进雨棚

  注意开 long long

 

CODE

技术图片
  1 #include <bits/stdc++.h>
  2 #define dbg(x) cout << #x << "=" << x << endl
  3 #define eps 1e-8
  4 #define pi acos(-1.0)
  5 
  6 using namespace std;
  7 typedef long long LL;
  8 
  9 const LL inf = 1e13;
 10 
 11 template<class T>inline void read(T &res)
 12 {
 13     char c;T flag=1;
 14     while((c=getchar())<0||c>9)if(c==-)flag=-1;res=c-0;
 15     while((c=getchar())>=0&&c<=9)res=res*10+c-0;res*=flag;
 16 }
 17 
 18 namespace _buff {
 19     const size_t BUFF = 1 << 19;
 20     char ibuf[BUFF], *ib = ibuf, *ie = ibuf;
 21     char getc() {
 22         if (ib == ie) {
 23             ib = ibuf;
 24             ie = ibuf + fread(ibuf, 1, BUFF, stdin);
 25         }
 26         return ib == ie ? -1 : *ib++;
 27     }
 28 }
 29 
 30 int qread() {
 31     using namespace _buff;
 32     int ret = 0;
 33     bool pos = true;
 34     char c = getc();
 35     for (; (c < 0 || c > 9) && c != -; c = getc()) {
 36         assert(~c);
 37     }
 38     if (c == -) {
 39         pos = false;
 40         c = getc();
 41     }
 42     for (; c >= 0 && c <= 9; c = getc()) {
 43         ret = (ret << 3) + (ret << 1) + (c ^ 48);
 44     }
 45     return pos ? ret : -ret;
 46 }
 47 
 48 const int maxn = 2007;
 49 
 50 int n, m;
 51 LL s[maxn], P[maxn];
 52 int S, T;
 53 
 54 struct edge{
 55     int from,to;
 56     LL cap,flow;
 57 };
 58 
 59 struct isap
 60 {
 61     int n,s,t;
 62     LL p[maxn],d[maxn],cur[maxn],num[maxn];
 63     vector<int>g[maxn];
 64     vector<edge> edges;
 65     void init(int n,int s,int t) {
 66         this->n = n;
 67         this->s = s;
 68         this->t = t;
 69         for(int i = 0;i <= 500;i++) g[i].clear();
 70         edges.clear();
 71         memset(p, 0, sizeof(p));
 72         memset(d, 0, sizeof(d));    
 73         memset(cur, 0, sizeof(cur));
 74         memset(num, 0, sizeof(num));
 75     }
 76     void addegde(int from,int to,int cap) {
 77         edges.push_back((edge){from, to, cap, 0});
 78         edges.push_back((edge){to, from, 0, 0});
 79         int m = edges.size();
 80         g[from].push_back(m-2);
 81         g[to].push_back(m-1);
 82     }
 83 
 84     LL augment() {///找增广路
 85         int d = edges.size();
 86         // for ( int i = 0; i < d; ++i ) {
 87         //     printf("from:%d to:%d cap:%d
",edges[i].from,edges[i].to,edges[i].cap);
 88         // }
 89         int x = t;
 90         LL a = inf;
 91 
 92         while(x!=s) {
 93             a = min(a, edges[p[x]].cap - edges[p[x]].flow);
 94             x = edges[p[x]].from;
 95             // printf("edges[%d].from:%d
",p[x], edges[p[x]].from);
 96             // printf("x:%d s:%d
",x, s);
 97         }
 98         x=t;
 99         while(x != s) {
100             edges[p[x]].flow += a;
101             edges[p[x]^1].flow = -a;
102             x = edges[p[x]].from;
103         }
104         return a;
105     }
106 
107     LL maxflow() {///更新最大流
108         LL flow = 0;
109         memset(num, 0, sizeof(num));
110         memset(cur, 0, sizeof(cur));
111         //memset(d, 0, sizeof(d));
112         for(int i = 1; i <= n; i++) num[d[i]]++;
113         int x = s;
114 
115         //printf("d[%d]:%d
",s, d[s]);
116         while(d[s] < n) {///最长的一条链上,最大的下标是nv-1,如果大于等于nv说明已断层
117             //printf("d[%d]:%d
", s, d[s]);
118             if(x == t) {
119                 flow += augment();
120                 x = s;//回退
121             }
122             bool ok = 0;
123             for(int i = cur[x]; i < g[x].size(); i++) {
124                 edge e = edges[g[x][i]];
125                 //printf("e->to:%d
",e.to);
126                 if(d[x] == d[e.to] + 1 && e.cap > e.flow) {
127                     p[e.to] = g[x][i];
128                     cur[x] = i;x = e.to;
129                     ok = 1;
130                     break;
131                 }
132             }
133             if(!ok) {
134                 LL m = n-1;
135                 for(int i = 0; i < g[x].size();i++) {
136                     edge &e=edges[g[x][i]];
137                     if(e.cap>e.flow) m=min(m,d[e.to]);
138                 }
139                 num[d[x]]--;
140                 if(!num[d[x]]) break;
141                 d[x] = m+1;
142                 num[d[x]]++;
143                 cur[x] = 0;
144                 if(x != s) x = edges[p[x]].from;
145             }
146         }
147         return flow;
148     }
149 }ISAP;
150 
151 LL dis[207][207];
152 
153 inline int id(int a, int b) {
154     return (a - 1) * n + b;
155 }
156 
157 bool check(LL x) {
158     ISAP.init(n * 3, 0, n * 2 + 1);
159     for ( int i = 1; i <= n; ++i ) {
160         for ( int j = 1; j <= n; ++j ) {
161             //printf("dis[%d][%d]:%d
",i, j, dis[i][j]);
162             if(dis[i][j] != inf && dis[i][j] <= x) {
163                 ISAP.addegde(i, j + n, inf);
164                 //printf("i:%d j+n:%d
",i, j + n);
165                 //ISAP.addegde(j + n, i, 0);
166             }
167         }
168     }
169     int S = 0, T = n * 2 + 1;
170     LL sum = 0;
171     for ( int i = 1; i <= n; ++i ) {
172         ISAP.addegde(S, i, s[i]);
173         sum += s[i];
174         ISAP.addegde(i + n, T, P[i]);
175         ISAP.addegde(i, i + n, inf);
176     }
177     LL res = ISAP.maxflow();
178     // dbg(res);
179     // dbg(sum);
180     return res == sum;
181 }
182 
183 int main()
184 {
185     //freopen("data.txt", "r", stdin);
186     read(n); read(m);
187     for ( int i = 1; i <= n; ++i ) {
188         read(s[i]); read(P[i]);
189     }
190     for ( int i = 1; i <= n; ++i ) {
191         for ( int j = 1; j <= n; ++j ) {
192             if(i == j)
193                 dis[i][j] = dis[j][i] = 0;
194             else {
195                 dis[i][j] = dis[j][i] = inf;
196             }
197         }
198     }
199     for ( int i = 1; i <= m; ++i ) {
200         LL u, v, c;
201         read(u); read(v); read(c);
202         if(dis[u][v] == inf || dis[u][v] > c) dis[u][v] = dis[v][u] = c;
203         //ISAP.addegde(u, v, c);
204     }
205     LL l = 0, r = 0, mid;
206     for ( int k = 1; k <= n; ++k ) {
207         for ( int i = 1; i <= n; ++i ) {
208             for ( int j = 1; j <= n; ++j ) {
209                 if(i == j) {
210                     dis[i][j] = 0;
211                 }
212                 else {
213                     if(dis[i][j] > dis[i][k] + dis[k][j]) {
214                         dis[i][j] = dis[i][k] + dis[k][j];
215                     }
216                 }
217                 r = max(r, dis[i][j]);
218             }
219         }
220     }
221     LL ans = -1;
222     while(l <= r) {
223         mid = (l + r) >> 1;
224         //dbg(mid);
225         if(check(mid)) {
226             ans = mid, r = mid - 1;
227         }
228         else {
229             l = mid + 1;
230         }
231     }
232     cout << ans << endl;
233     return 0;
234 }
View Code

 

#include <bits/stdc++.h>
#define dbg(x) cout << #x << "=" << x << endl
#define eps 1e-8
#define pi acos(-1.0)

using namespace std;
typedef long long LL;

const LL inf = 1e13;

template<class T>inline void read(&res)
{
    char c;T flag=1;
    while((c=getchar())<0||c>9)if(c==-)flag=-1;res=c-0;
    while((c=getchar())>=0&&c<=9)res=res*10+c-0;res*=flag;
}

namespace _buff {
    const size_t BUFF = 1 << 19;
    char ibuf[BUFF], *ib = ibuf, *ie = ibuf;
    char getc() {
        if (ib == ie) {
            ib = ibuf;
            ie = ibuf + fread(ibuf, 1, BUFF, stdin);
        }
        return ib == ie ? -1 : *ib++;
    }
}

int qread() {
    using namespace _buff;
    int ret = 0;
    bool pos = true;
    char c = getc();
    for (; (< 0 || c > 9) && c != -; c = getc()) {
        assert(~c);
    }
    if (== -) {
        pos = false;
        c = getc();
    }
    for (; c >= 0 && c <= 9; c = getc()) {
        ret = (ret << 3) + (ret << 1) + (^ 48);
    }
    return pos ? ret : -ret;
}

const int maxn = 2007;

int n, m;
LL s[maxn], P[maxn];
int S, T;

struct edge{
    int from,to;
    LL cap,flow;
};

struct isap
{
    int n,s,t;
    LL p[maxn],d[maxn],cur[maxn],num[maxn];
    vector<int>g[maxn];
    vector<edge> edges;
    void init(int n,int s,int t) {
        this->n = n;
        this->s = s;
        this->t = t;
        for(int i = 0;<= 500;i++) g[i].clear();
        edges.clear();
        memset(p, 0, sizeof(p));
        memset(d, 0, sizeof(d));    
        memset(cur, 0, sizeof(cur));
        memset(num, 0, sizeof(num));
    }
    void addegde(int from,int to,int cap) {
        edges.push_back((edge){from, to, cap, 0});
        edges.push_back((edge){to, from, 0, 0});
        int m = edges.size();
        g[from].push_back(m-2);
        g[to].push_back(m-1);
    }

    LL augment() {///找增广路
        int d = edges.size();
        // for ( int i = 0; i < d; ++i ) {
        //     printf("from:%d to:%d cap:%d ",edges[i].from,edges[i].to,edges[i].cap);
        // }
        int x = t;
        LL a = inf;

        while(x!=s) {
            a = min(a, edges[p[x]].cap - edges[p[x]].flow);
            x = edges[p[x]].from;
            // printf("edges[%d].from:%d ",p[x], edges[p[x]].from);
            // printf("x:%d s:%d ",x, s);
        }
        x=t;
        while(!= s) {
            edges[p[x]].flow += a;
            edges[p[x]^1].flow = -a;
            x = edges[p[x]].from;
        }
        return a;
    }

    LL maxflow() {///更新最大流
        LL flow = 0;
        memset(num, 0, sizeof(num));
        memset(cur, 0, sizeof(cur));
        //memset(d, 0, sizeof(d));
        for(int i = 1; i <= n; i++) num[d[i]]++;
        int x = s;

        //printf("d[%d]:%d ",s, d[s]);
        while(d[s] < n) {///最长的一条链上,最大的下标是nv-1,如果大于等于nv说明已断层
            //printf("d[%d]:%d ", s, d[s]);
            if(== t) {
                flow += augment();
                x = s;//回退
            }
            bool ok = 0;
            for(int i = cur[x]; i < g[x].size(); i++) {
                edge e = edges[g[x][i]];
                //printf("e->to:%d ",e.to);
                if(d[x] == d[e.to] + 1 && e.cap > e.flow) {
                    p[e.to] = g[x][i];
                    cur[x] = i;= e.to;
                    ok = 1;
                    break;
                }
            }
            if(!ok) {
                LL m = n-1;
                for(int i = 0; i < g[x].size();i++) {
                    edge &e=edges[g[x][i]];
                    if(e.cap>e.flow) m=min(m,d[e.to]);
                }
                num[d[x]]--;
                if(!num[d[x]]) break;
                d[x] = m+1;
                num[d[x]]++;
                cur[x] = 0;
                if(!= s) x = edges[p[x]].from;
            }
        }
        return flow;
    }
}ISAP;

LL dis[207][207];

inline int id(int a, int b) {
    return (- 1) * n + b;
}

bool check(LL x) {
    ISAP.init(* 3, 0, n * 2 + 1);
    for ( int i = 1; i <= n; ++) {
        for ( int j = 1; j <= n; ++) {
            //printf("dis[%d][%d]:%d ",i, j, dis[i][j]);
            if(dis[i][j] != inf && dis[i][j] <= x) {
                ISAP.addegde(i, j + n, inf);
                //printf("i:%d j+n:%d ",i, j + n);
                //ISAP.addegde(j + n, i, 0);
            }
        }
    }
    int S = 0, T = n * 2 + 1;
    LL sum = 0;
    for ( int i = 1; i <= n; ++) {
        ISAP.addegde(S, i, s[i]);
        sum += s[i];
        ISAP.addegde(+ n, T, P[i]);
        ISAP.addegde(i, i + n, inf);
    }
    LL res = ISAP.maxflow();
    // dbg(res);
    // dbg(sum);
    return res == sum;
}

int main()
{
    //freopen("data.txt", "r", stdin);
    read(n); read(m);
    for ( int i = 1; i <= n; ++) {
        read(s[i]); read(P[i]);
    }
    for ( int i = 1; i <= n; ++) {
        for ( int j = 1; j <= n; ++) {
            if(== j)
                dis[i][j] = dis[j][i] = 0;
            else {
                dis[i][j] = dis[j][i] = inf;
            }
        }
    }
    for ( int i = 1; i <= m; ++) {
        LL u, v, c;
        read(u); read(v); read(c);
        if(dis[u][v] == inf || dis[u][v] > c) dis[u][v] = dis[v][u] = c;
        //ISAP.addegde(u, v, c);
    }
    LL l = 0, r = 0, mid;
    for ( int k = 1; k <= n; ++) {
        for ( int i = 1; i <= n; ++) {
            for ( int j = 1; j <= n; ++) {
                if(== j) {
                    dis[i][j] = 0;
                }
                else {
                    if(dis[i][j] > dis[i][k] + dis[k][j]) {
                        dis[i][j] = dis[i][k] + dis[k][j];
                    }
                }
                r = max(r, dis[i][j]);
            }
        }
    }
    LL ans = -1;
    while(<= r) {
        mid = (+ r) >> 1;
        //dbg(mid);
        if(check(mid)) {
            ans = mid, r = mid - 1;
        }
        else {
            l = mid + 1;
        }
    }
    cout << ans << endl;
    return 0;
}

以上是关于P2402 奶牛隐藏二分最大流的主要内容,如果未能解决你的问题,请参考以下文章

POJ 2112 Optimal Milking(二分+最大流)

POJ 2112 /// 最大流+floyd+二分

POJ 2112 Optimal Milking (二分+最短路+最大流)

POJ-2112 Optimal Milking(floyd+最大流+二分)

poj2122 Optimal Milking

洛谷 P1824 进击的奶牛 二分答案(求最大的最小值)