zoukankan      html  css  js  c++  java
  • POJ1459 Power Network 网络流 最大流

    原文链接http://www.cnblogs.com/zhouzhendong/p/8326021.html


    题目传送门 - POJ1459


    题意概括

      多组数据。

      对于每一组数据,首先一个数n,表示有n个保安(n=0时输入结束)。

        接下来分别描述n个保安的信息。

        对于每一个保安,首先两个整数K,M,分别表示他的空余时间段数和他一天中的最多工作时间。

          接下来K行,每行h1:m1 h2:m2格式输入两个时间点,表示他从h1:m1时刻到h2:m2时刻是空余的。

      现在我们要安排保安。

      保安的开始工作和结束工作时间只可以安排在整点或者半点,即m=0或m=30。

      现在对于每一组数据,我们问一天中保安数量最少的时刻最多有多少个保安。


    题解

      网络流学习资源链接 -> 传送门

      假如我们已经知道了答案,答案为ans。

      那么我们可以考虑判断这个答案的正确性。

      我们搞一个超级源点S和一个超级汇点T,然后把所有的保安当作节点,所有的时刻当作节点。

      那么我们构图方法就很简单了。

      由于保安的开始工作和结束工作时间只可以安排在整点或者半点,所以我们划分一下时刻,把所有的时间段划分成48个。

    • 对于每一个保安Pi,我们建立一条S->Pi的边,容量为Mi div 30
    • 对于每一个保安Pi,如果他在第Tj个时间段是空闲的,那么我们建立一条Pi->Tj的边,容量为1
    • 对于每一个时间点Ti,我们建立一条Ti->T的边,容量为ans

      如此建边,我们就只需要跑一跑最大流,然后看最大流是不是等于ans*48就可以了。

      于是我们推广出两种算法:

      二分答案  VS  逐个添加

      本人更倾向于逐个添加,因为网络流的特殊性质。


    代码

    #include <cstring>
    #include <cstdio>
    #include <algorithm>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    const int N=48+50+5,M=(50*48*2+48+50)*2+233;
    bool isd(char ch){
    	return '0'<=ch&&ch<='9';
    }
    int read(){
    	int res=0,f=1;
    	char ch=getchar();
    	while (!isd(ch)&&ch!='-')
    		ch=getchar();
    	if (ch=='-')
    		f=-1,ch=getchar();
    	while (isd(ch))
    		res=(res<<3)+(res<<1)+ch-48,ch=getchar();
    	return res*f;
    }
    int n,Free[1440];
    struct edge{
    	int x,y,cap,flow,nxt;
    };
    struct gragh{
    	int cnt,fst[N],dist[N],n,S,T,cur[N],num[N],p[N];
    	int q[N],head,tail;
    	edge e[M];
    	void set(int _S,int _T,int _n){
    		S=_S,T=_T,n=_n,cnt=1;
    		memset(fst,0,sizeof fst);
    	}
    	void add(int a,int b,int c){
    		cnt++;
    		e[cnt].x=a,e[cnt].y=b,e[cnt].cap=c,e[cnt].flow=0;
    		e[cnt].nxt=fst[a],fst[a]=cnt;
    		cnt++;
    		e[cnt].x=b,e[cnt].y=a,e[cnt].cap=0,e[cnt].flow=0;
    		e[cnt].nxt=fst[b],fst[b]=cnt;
    	}
    	void bfs(){
    		memset(dist,-1,sizeof dist);
    		head=tail=dist[T]=0,q[++tail]=T;
    		while (head<tail)
    			for (int x=q[++head],y,i=fst[x];i;i=e[i].nxt)
    				if (e[i].cap==0&&dist[y=e[i].y]==-1)
    					dist[q[++tail]=y]=dist[x]+1;
    		for (int i=1;i<=n;i++)
    			if (dist[i]==-1)
    				dist[i]=n;
    	}
    	void init(){
    		bfs();
    		memset(num,0,sizeof num);
    		for (int i=1;i<=n;i++)
    			num[dist[i]]++,cur[i]=fst[i];
    	}
    	int Augment(int &x){
    		int ex_flow=1e9;
    		for (int i=T;i!=S;i=e[p[i]].x)
    			if (e[p[i]].cap-e[p[i]].flow<=ex_flow)
    				ex_flow=e[p[i]].cap-e[p[i]].flow,x=e[p[i]].x;
    		for (int i=T;i!=S;i=e[p[i]].x)
    			e[p[i]].flow+=ex_flow,e[p[i]^1].flow-=ex_flow;
    		return ex_flow;
    	}
    	int ISAP(){
    		int x=S,y,MaxFlow=0;
    		init();
    		while (dist[S]<n){
    			if (x==T){
    				MaxFlow+=Augment(x);
    				continue;
    			}
    			bool found=0;
    			for (int i=cur[x];i;i=e[i].nxt){
    				y=e[i].y;
    				if (dist[y]+1==dist[x]&&e[i].cap>e[i].flow){
    					p[y]=cur[x]=i,x=y,found=1;
    					break;
    				}
    			}
    			if (!found){
    				int d=n+1;
    				for (int i=fst[x];i;i=e[i].nxt)
    					if (e[i].cap>e[i].flow)
    						d=min(d,dist[e[i].y]+1);
    				if (!--num[dist[x]])
    					return MaxFlow;
    				num[dist[x]=d]++,cur[x]=fst[x],x=x==S?x:e[p[x]].x;
    			}
    		}
    		return MaxFlow;
    	}
    }g;
    bool check(int st,int en){
    	for (int i=st;i<en;i++)
    		if (!Free[i])
    			return 0;
    	return 1;
    }
    void solve(){
    	int S=1,T=2;
    	g.set(S,T,n+48+2);
    	for (int i=1;i<=n;i++){
    		int a=read(),b=read();
    		memset(Free,0,sizeof Free);
    		g.add(S,i+2,b/30);
    		for (int j=1;j<=a;j++){
    			int h1=read(),m1=read(),h2=read(),m2=read();
    			int v1=h1*60+m1,v2=h2*60+m2;
    			if (v1<v2)
    				for (int k=v1;k<v2;k++)
    					Free[k]=1;
    			else {
    				for (int k=v1;k<1440;k++)
    					Free[k]=1;
    				for (int k=0;k<v2;k++)
    					Free[k]=1;
    			}
    		}
    		for (int j=1;j<=48;j++)
    			if (check((j-1)*30,j*30))
    				g.add(i+2,n+j+2,1);
    	}
    	int ans=0;
    	for (int i=1;i<=48;i++)
    		g.add(n+i+2,T,1);
    	while (g.ISAP()==48){
    		ans++;
    		for (int i=1;i<=48;i++)
    			g.add(n+i+2,T,1);
    	}
    	printf("%d
    ",ans);
    }
    int main(){
    	while (n=read())
    		solve(); 
    	return 0;
    }
    

      

  • 相关阅读:
    对象并不一定都是在堆上分配内存的
    Minor GC、Major GC和Full GC之间的区别
    JAVA内存分配与回收策略
    HotSpot虚拟机对象相关内容
    JAVA运行时数据区域
    Java 的强引用、弱引用、软引用、虚引用
    去哪儿网支付系统架构演进(下篇)
    去哪儿网支付系统架构演进(上)
    心智模式:如何改善我们的心智模式?
    心智模式:心智模式成熟的标志
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/POJ1459.html
Copyright © 2011-2022 走看看