zoukankan      html  css  js  c++  java
  • poj 2112

    网络流之最大流。此题的关键就是建模,看了题目之后一点思路都没有,后来在网上看了解题报告后,才明白了这个过程。首先,在原图中抽象出一个新图。新图是由旧图中的每个milking machine到每个cow的最短路径组成,每条最短路径由原图中的各点间的某些路径组成,抽象为新图中的一条路径,此过程通过floyd算法(各顶点间的最短路径)实现。接下来,就是通过二分来枚举答案。通过给出一个流量的上限,给新图的路径的容量cap赋值,如果小于等于上限cap就为1,反之为0。最后就可将问题转化为新图中,从各milk machine(即源点s)到各cow(即终点t)的最大流(一个流就对应与一头牛)(其实还不完整),如果最大流>=cow的个数,说明当前方案可行,枚举下一个值,最后由二分得到最优解。其中多源多终点问题,可通过加一个超级源和超级终点来转换为一源一终最大流问题。其实,还有一个问题没有解决,就是每台milk machine最大的工作量为m,现在有个超级源就可以很完美的规划为网络流问题。通过设定超级源到每个源点的容量为m,那么由流网络中的流守恒定理可知,从超级源流到各源的上限就是个从各源流出的流的上限,也即各milk machine所能服务的cow的上限。还有一个很明显的问题就是,一个牛肯定只能接受一个流,所以设定各个终点到超级终点的路径的容量设为1。其中最大流算法用的是EK,很慢,但目前还没掌握dinic和isap,这几天要抓紧学啊。

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <queue>
    using namespace std;
    const int maxn=250;
    const int inf=1<<20;//刚开始inf定义的过大,导致求dis[i][j]时,使两个inf相加的和溢出,得到一个错的dis[i][j],以后要注意这个问题
    int dis[maxn][maxn],cap[maxn][maxn],flow[maxn][maxn];
    int k,c,m,t;
    void floyd()
    {
    	int i,j,k;
    	for(k=1;k<=t;k++)
    	{
    		for(i=1;i<=t;i++)
    		{
    			for(j=1;j<=t;j++)
    				dis[i][j]=dis[i][j]<(dis[i][k]+dis[k][j])?dis[i][j]:(dis[i][k]+dis[k][j]);//防止溢出,所以inf不能定义的过大
    		}
    	}
    }
    void build(int limit)
    {
    	memset(cap,0,sizeof(cap));
    	int i,j;
    	for(i=1;i<=k;i++) cap[0][i]=m;
    	for(i=k+1;i<=t;i++) cap[i][t+1]=1;
    	for(i=1;i<=k;i++)
    	{
    		for(j=k+1;j<=t;j++)
    			if(dis[i][j]<inf&&dis[i][j]<=limit) cap[i][j]=1;
    	}
    }
    bool ek()
    {
    	queue<int> q;
    	int a[maxn],p[maxn],tot=0,i;
    	memset(flow,0,sizeof(flow));
    	for(;;)
    	{
    		memset(a,0,sizeof(a));
    		a[0]=inf;
    		q.push(0);
    		while(!q.empty())
    		{
    			int x=q.front();
    			q.pop();
    			for(i=0;i<=t+1;i++)
    			{
    				if(!a[i]&&(cap[x][i]-flow[x][i])>0)
    				{
    					p[i]=x;
    					a[i]=a[x]>(cap[x][i]-flow[x][i])?(cap[x][i]-flow[x][i]):a[x];
    					q.push(i);
    				}
    			}
    		}
    		if(!a[t+1]) break;
    		for(i=t+1;i!=0;i=p[i])
    		{
    			flow[p[i]][i]+=a[t+1];
    			flow[i][p[i]]-=a[t+1];
    		}
    		tot+=a[t+1];
    	}
    	if(tot<c) return false;
    	else return true;
    }
    int binarysearch()
    {
    	int high=230*200+1,low=0,mid;
    	while(high-low>0)
    	{
    		mid=low+(high-low)/2;
    		build(mid);
    		if(ek()) high=mid;
    		else low=mid+1;
    	}
    	return high;
    }
    int main()
    {
    	while(scanf("%d%d%d",&k,&c,&m)!=EOF)
    	{
    		int i,j;
    		t=k+c;
    		for(i=1;i<=t;i++)
    		{
    			for(j=1;j<=t;j++)
    			{
    				scanf("%d",&dis[i][j]);
    				if(!dis[i][j]&&i!=j) dis[i][j]=inf;
    			}
    		}
    		floyd();
    		int result=binarysearch();
    		cout<<result<<endl;
    	}
    	return 0;
    }


  • 相关阅读:
    如何判断某个变量是否是数组?
    mac vscode编辑器的快捷键
    vue require.context()动态文件引入
    在vue项目上使用less
    nrm是什么
    对象的扩展方法
    es5严格模式
    微信公众号定位不准问题
    layer使用iframe的路径不对问题
    form表单中reset对js赋值的表单象无法重置问题
  • 原文地址:https://www.cnblogs.com/lj030/p/3002340.html
Copyright © 2011-2022 走看看