• BZOJ 1570: [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

     
    题解:
      这个题目一开始都不知道是最大流。
      首先分析一下这个题,如果往网络流的方向去想的话,就可以把人看成水流,这个就可以变成一个标准的网络流模型。
      但怎么连边?如果直接连的话,感觉非常有道理,但是没有办法知道答案,所以我们可以对这个图按照天数分层,枚举需要几天才可以跑完,然后建立分层图,如果当的最大流==人数的话就是可行的。否则就不行。
      注意:要加玄学剪枝:if(!tag) dis[now]=0,然后就记得将跑过的图还原就可以了。
     
    代码:
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #include <queue>
    #define MAXN 100010
    #define inf 1<<30
    using namespace std;
    int dis[MAXN];queue<int> q;
    struct edge{
        int first;
        int next;
        int to;
        int caw;
    }a[MAXN*2];
    int u[MAXN],v[MAXN],can[MAXN];
    int S=0,T=MAXN-5,n,m,k,num=1;
    void rezero(){
        for(int i=2;i<=num;i+=2){
            a[i].caw+=a[i^1].caw,a[i^1].caw=0;
        }
    }
    
    void addedge(int from,int to,int caw){
        a[++num].to=to;
        a[num].caw=caw;
        a[num].next=a[from].first;
        a[from].first=num;
    }
    
    void link(int x,int y,int z){
        addedge(x,y,z),addedge(y,x,0);
    }
    
    bool bfs(){
        memset(dis,0,sizeof(dis));
        while(!q.empty()) q.pop();
        dis[S]=1;q.push(S);
        while(!q.empty()){
            int now=q.front();q.pop();
            for(int i=a[now].first;i;i=a[i].next){
                int to=a[i].to,caw=a[i].caw;
                if(!dis[to]&&caw){
                    dis[to]=dis[now]+1;
                    q.push(to);
                    if(to==T) return 1;
                }
            }
        }
        return 0;
    }
    
    int dfs(int now,int flow){
        if(now==T) return flow;
        int tag=0;
        for(int i=a[now].first;i;i=a[i].next){
            int to=a[i].to,caw=a[i].caw;
            if(dis[to]==dis[now]+1&&caw){
                int minn=dfs(to,min(caw,flow-tag));
                a[i].caw-=minn;
                a[i^1].caw+=minn;
                tag+=minn;
                if(tag==flow) return tag;
            }
        }
        if(!tag) dis[now]=0;
        return tag;
    }
    
    int dinic(){
        int maxflow=0;
        while(bfs()){
            maxflow+=dfs(S,inf);
        }
        return maxflow;
    }
    
    int main()
    {    
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=m;i++) scanf("%d%d%d",&u[i],&v[i],&can[i]);
        link(S,1,k);
        for(int day=1;day<=n+k;day++){
            rezero();
            for(int i=1;i<=m;i++) link((day-1)*n+u[i],n*day+v[i],can[i]);
            for(int i=1;i<=n;i++) link((day-1)*n+i,n*day+i,inf);
            link(day*n+n,T,inf);
            int hh=dinic();
            if(hh>=k){
                printf("%d
    ",day);
                return 0;
            }
        }
        puts("-1");
        return 0;
    }
  • 相关阅读:
    Android 关于ExpandableListView控件setOnChildClickListener无效问题
    Android SnapHelper
    Android java判断字符串包含某个字符段(或替换)
    Android中的CharSequence和String
    Java时间和时间戳的相互转换
    比较运算符和函数(四十一)
    数值运算符和函数(四十)
    字符函数(三十九)
    多表删除(三十八)
    无限级分类表设计(三十七)
  • 原文地址:https://www.cnblogs.com/renjianshige/p/7635566.html
Copyright © 2020-2023  润新知