zoukankan      html  css  js  c++  java
  • 【BZOJ1570】[JSOI2008]Blue Mary的旅行 动态加边网络流

    【BZOJ1570】[JSOI2008]Blue Mary的旅行

    Description

    在一段时间之后,网络公司终于有了一定的知名度,也开始收到一些订单,其中最大的一宗来自B市。Blue Mary决定亲自去签下这份订单。为了节省旅行经费,他的某个金融顾问建议只购买U航空公司的机票。U航空公司的所有航班每天都只有一班,并且都是上午出发当天下午到达的,所以他们每人每天只能坐一班飞机。经过调查,他们得到了U航空公司经营的所有航班的详细信息,这包括每一航班的出发地,目的地以及最多能买到的某一天出发的票数。(注意: 对于一个确定的航班,无论是哪一天,他们最多能买到的那一天出发的票数都是相同的。) Blue Mary注意到他们一定可以只乘坐U航空公司的航班就从A市到达B市,但是,由于每一航班能买到的票的数量的限制,他们所有人可能不能在同一天到达B市。所以现在Blue Mary需要你的帮助,设计一个旅行方案使得最后到达B市的人的到达时间最早。

    Input

    第一行包含3个正整数N,M和T。题目中会出现的所有城市分别编号为1,2,…,N,其中城市A编号一定为1,城市B编号一定为N. U公司一共有M条(单向)航班。而连Blue Mary在内,公司一共有T个人要从A市前往B市。 以下M行,每行包含3个正整数X,Y,Z, 表示U公司的每一条航班的出发地,目的地以及Blue Mary最多能够买到的这一航班某一天出发的票数。(即:无论是哪一天,Blue Mary最多只能买到Z张U航空公司的从城市X出发到城市Y的机票。) 输入保证从一个城市到另一个城市的单向航班最多只有一个。

    Output

    仅有一行,包含一个正整数,表示最后到达B市的人的最早到达时间。假设他们第一次乘飞机的那一天是第一天。

    Sample Input

    3 3 5
    1 2 1
    2 3 5
    3 1 4

    Sample Output

    6

    HINT

    约定:
    2 <= N <= 50
    1 <= M <= 2450
    1 <= T <= 50
    1 <= X,Y <= N
    X != Y
    1 <= Z <= 50

    题解:我们假设在tim时所有人都能到达终点,于是我们枚举tim,将每个点拆成tim个,然后连边跑最大流,若流量=T,说明tim就是答案

    具体方法:用(i,j)表示将原来的i号节点拆成第j个点
    1.S -> (0,0) 流量T
    2.(i,j-1) -> (i,j) 流量∞
    3.对于边(a,b,c) (a,j-1) -> (b,j) 流量c
    4.(n,j) -> T 流量T

    由于本人觉得点数比较多,感到很虚,所以用了动态加边的最大流,56ms飞起~

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    #define P(A,B)	((B)*n+A)
    using namespace std;
    
    int to[1000000],next[1000000],val[1000000],d[50010],head[50010],pa[2500],pb[2500],pc[2500];
    int n,m,t,cnt,ans,sum,S,T,tim;
    queue<int> q;
    int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    void add(int a,int b,int c)
    {
    	to[cnt]=b,val[cnt]=c,next[cnt]=head[a],head[a]=cnt++;
    	to[cnt]=a,val[cnt]=0,next[cnt]=head[b],head[b]=cnt++;
    }
    int bfs()
    {
    	int i,u;
    	memset(d,0,sizeof(d));
    	while(!q.empty())	q.pop();
    	d[S]=1,q.push(S);
    	while(!q.empty())
    	{
    		u=q.front(),q.pop();
    		for(i=head[u];i!=-1;i=next[i])
    		{
    			if(!d[to[i]]&&val[i])
    			{
    				d[to[i]]=d[u]+1;
    				if(to[i]==T)	return 1;
    				q.push(to[i]);
    			}
    		}
    	}
    	return 0;
    }
    int dfs(int x,int mf)
    {
    	if(x==T)	return mf;
    	int i,temp=mf,k;
    	for(i=head[x];i!=-1;i=next[i])
    	{
    		if(d[to[i]]==d[x]+1&&val[i])
    		{
    			k=dfs(to[i],min(temp,val[i]));
    			if(!k)	d[to[i]]=0;
    			val[i]-=k,val[i^1]+=k,temp-=k;
    			if(!temp)	break;
    		}
    	}
    	return mf-temp;
    }
    int main()
    {
    	n=rd(),m=rd(),t=rd(),tim=n+t;
    	S=0,T=n*(tim+1)+1;
    	memset(head,-1,sizeof(head));
    	add(S,1,t);
    	int i,j,k,a,b,c;
    	for(i=1;i<=m;i++)	pa[i]=rd(),pb[i]=rd(),pc[i]=rd();
    	for(i=1;i<=tim;i++)
    	{
    		for(j=1;j<=m;j++)	add(P(pa[j],i-1),P(pb[j],i),pc[j]);
    		for(j=1;j<=n;j++)	add(P(j,i-1),P(j,i),1<<30);
    		add(P(n,i),T,t);
    		while(bfs())	sum+=dfs(S,1<<30);
    		if(sum==t)
    		{
    			printf("%d",i);
    			return 0;
    		}
    	}
    }
  • 相关阅读:
    转:UFLDL_Tutorial 笔记(deep learning绝佳的入门资料 )
    转:使用RNN解决NLP中序列标注问题的通用优化思路
    CTR预估中GBDT与LR融合方案
    ZOJ1157, POJ1087,UVA 753 A Plug for UNIX (最大流)
    Gentoo:startx出现Failed to load module问题
    HTTP请求和响应2:方法(Method)
    SharePoint 2013 表单认证使用ASP.Net配置工具加入用户
    理解支持向量机(四)LibSVM工具包的使用
    LeetCode 14: Longest Common Prefix
    精通Hibernate——域对象之间的关系
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/6855711.html
Copyright © 2011-2022 走看看