poj2112网络流扩展

poj2112网络流扩展

  • 题目来源:http://poj.org/problem?id=2112
    这题在读题的时候根本没意思到这个可以用网络流最大流来做,看了别人博客才知道。╮(╯▽╰)╭我果然还是渣渣

题目部分

  • 题意:
    农场主有K台机器,有C头牛,每台机器可以服务M头牛,现在农场主要把机器放在牛群之中。
    把牛和机器都看成一个点,编号从1开始,编号前1到K是机器,K+1到K+C是牛,给你一个二维矩阵,0代表没有直接相连的路(但是不代表两点之间不能到达,他们可以通过与其他点相连就可以到达)。
    题目要求出,最远的牛到达服务这头牛的距离的最小值(服务方式不同最远距离就会不同)
  • 思路:
    (╮(╯▽╰)╭没看出来可以用网络流做吧)
    这里要先用Floyd算出点与点之间的距离,这样就可以得到牛与机器之间路径的距离了。
    接下来就是开始2分法穷举了,我们把Floyd获得的距离中最长right与最短left的边获取出来,用二分法进行尝试。
    把二分法的mid值假设成是最终答案,这样就可以把图中大于mid的边忽略掉,建立一个网络图,源点与机器相连,边的值为每台机器可以服务的M,汇点与牛相连,边的值为1,把机器到牛且边的值小于等于mid的加入到网络流里。
    这样如果这个网络流图的最大流的值是牛的总数C那么mid这个值可能是答案,我们缩小搜索范围,right = mid,如果最大流不等于C,则这个值不可能是答案,因为不是所有牛都被服务到,继续缩小搜索范围,left = mid+1,直到left>=right退出二分搜索,此时right必然是最终答案(题目有说一句肯定存在一种每头牛都被服务的方式,所以这个是可行的。我只能解释到这了,语文能力不够咕~~(╯﹏╰)b)

代码部分

主要注意初始化,每次都二分都需要进行构建网络流图。

#include<iostream>
#include<algorithm>
#include<fstream>
#include<math.h>
#include<algorithm>
#include<stack>
#include<queue>
using namespace std;
fstream fin("1.txt");
//streambuf *buf = cin.rdbuf(fin.rdbuf());

const int inf = 1 << 29;
const int MAXN = 310;

int k, c, m, n;
int map[MAXN][MAXN];
int network[MAXN][MAXN];
int pre[MAXN];
bool vis[MAXN];

void init()
{
    for (int i = 0; i <= n; i++)
    {
        for (int j = 0; j <= n; j++)
        {
            map[i][j] = 0;
        }
    }
}
int getmin(int a, int b)
{
    return a < b ? a : b;
}
int getmax(int a, int b)
{
    return a > b ? a : b;
}
void builtmap(int limit)
{
    int s = n + 1;
    int e = n + 2;
    for (int i = 0; i <= e; i++)
    {
        for (int j = 0; j <= e; j++)
        {
            network[i][j] = 0;
        }
    }
    for (int i = 1; i <= k; i++)//机器和源点连接,边的权值为m,每台机器可服务牛数
    {
        network[s][i] = m;
    }
    for (int i = k + 1; i <= n; i++)//牛和汇点连接,边的权值为1
    {
        network[i][e] = 1;
    }
    for (int i = 1; i <= k; i++)//满足条件的机器到牛的边
    {
        for (int j = k + 1; j <= n; j++)
        {
            if (map[i][j] && map[i][j] <= limit)
            {
                network[i][j] = 1;
            }
        }
    }
}
int bfs(int s, int e)
{
    int temp;
    for (int i = 0; i <= e; i++)
    {
        pre[i] = 0;
        vis[i] = false;
    }
    pre[s] = 0;
    vis[s] = true;
    queue<int> que;
    que.push(s);
    bool haveroute = false;
    while (!haveroute && !que.empty())
    {
        temp = que.front();
        que.pop();
        for (int i = 0; i <= e; i++)
        {
            if (network[temp][i] && !vis[i])
            {
                pre[i] = temp;
                vis[i] = true;
                if (i == e)
                {
                    haveroute = true;
                    break;
                }
                que.push(i);
            }
        }
    }
    if (!haveroute)
    {
        return 0;
    }
    int minflow = inf;
    int t = e;
    while (pre[t])
    {
        minflow = getmin(minflow, network[pre[t]][t]);
        t = pre[t];
    }
    t = e;
    while (pre[t])
    {
        network[pre[t]][t] -= minflow;
        network[t][pre[t]] += minflow;
        t = pre[t];
    }
    return minflow;
}
int getflow()
{
    int s = n + 1;
    int e = n + 2;
    int ans = 0;
    int result;
    while (result = bfs(s, e))
    {
        ans += result;
    }
    return ans;
}
int main()
{
    while (cin >> k >> c >> m)
    {
        n = k + c;
        init();
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                cin >> map[i][j];
            }
        }
        //floyd求点与点的最小距离
        int maxroute = 0;//记录图中最大距离
        for (int k = 1; k <= n; k++)
        {
            for (int i = 1; i <= n; i++)
            {
                for (int j = 1; j <= n; j++)
                {
                    if (i == j)
                        continue;
                    if (map[i][k] && map[k][j] && (map[i][j] > map[i][k] + map[k][j] || map[i][j] == 0))
                        map[i][j] = map[i][k] + map[k][j];
                }
            }
        }
        //求出最大边
        for (int i = 1; i <= n; i++)
        {
            for (int j = 1; j <= n; j++)
            {
                if (map[i][j])
                {
                    maxroute = getmax(maxroute, map[i][j]);
                }
            }
        }
        //我这里没求最小边就直接用0来替代
        int left = 0, right = maxroute;
        int result = maxroute;
        int mid, maxflow;
        while (left <= right)
        {
            mid = (left + right) >> 1;
            builtmap(mid);
            maxflow = getflow();
            if (maxflow >= c)
            {
                result = mid;
                right = mid - 1;
            }
            else
                left = mid + 1;
        }
        cout << result << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值