bzoj3931: [CQOI2015]网络吞吐量

http://www.lydsy.com/JudgeOnline/problem.php?id=3931

 

在最短路网络上跑最大流

 

#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

const LL inf=1e16;

void read(int &x)
{
    x=0; char c=getchar();
    while(!isdigit(c))  c=getchar(); 
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar();  }
}

struct NetworkFlow
{
    #define N 1100
    #define M 260000
    
    int tot;
    int front[N],nxt[M<<1],to[M<<1],from[M<<1];
    LL val[M<<1];
    
    int lev[N],num[N];
    int path[N];
    int cur[N];
     
    int src,decc;
    
    int cap[501];
    
    /*int se[501];
    int edge[501][501];*/
    
    void add(int u,int v,LL w)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; from[tot]=u; val[tot]=w;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; from[tot]=v; val[tot]=0;
    }
    
    bool bfs()
    {
        queue<int>q;
        for(int i=src;i<=decc;++i) lev[i]=decc-src+1;
        q.push(decc);
        lev[decc]=0;
        int now,t;
        while(!q.empty())
        {
            now=q.front();
            q.pop();
            for(int i=front[now];i;i=nxt[i])
            {
                t=to[i];
                if(lev[t]==decc-src+1 && val[i^1]) 
                {
                    lev[t]=lev[now]+1;
                    q.push(t);
                }
            }
        }
        return lev[src]!=decc-src+1;
    }
     
    int augment()
    {
        int now=decc;
        LL flow=inf;
        int i;
        while(now!=src)
        {
            i=path[now];
            flow=min(flow,val[i]);
            now=from[i];
        }
        now=decc;
        while(now!=src)
        {
            i=path[now];
            val[i]-=flow;
            val[i^1]+=flow;
            now=from[i];
        }
        return flow;
    }
     
    LL isap()
    {
        LL flow=0;
        if(!bfs()) return 0;
        memset(num,0,sizeof(num));
        for(int i=src;i<=decc;++i) num[lev[i]]++,cur[i]=front[i];
        int now=src,t;
        while(lev[src]<=decc-src)
        {
            if(now==decc)
            {
                flow+=augment();
                now=src;
            }
            bool advanced=false;
            for(int i=cur[now];i;i=nxt[i])
            {
                t=to[i];
                if(lev[t]==lev[now]-1 && val[i])
                {
                    advanced=true;
                    path[t]=i;
                    cur[now]=i;
                    now=t;
                    break;
                }
            }
            if(!advanced)
            {
                int mi=decc;
                for(int i=front[now];i;i=nxt[i])
                    if(val[i]) mi=min(mi,lev[to[i]]);
                if(!--num[lev[now]]) break;
                num[lev[now]=mi+1]++;
                cur[now]=front[now];
                if(now!=src) now=from[path[now]];
            }
        }
        return flow;
    }
    
    void build(int n)
    {
        //for(int i=1;i<=n;++i) cout<<se[i]<<'\n';
        src=3;
        decc=n<<1;
        for(int i=2;i<n;++i) add(i<<1,i<<1|1,cap[i]);
        /*for(int i=1;i<=n;++i)
        {
            for(int j=1;j<=se[i];++j)
                add(i<<1|1,edge[i][j]<<1,inf);
        }*/
    }
    
    #undef N
    #undef M

}Net;

struct Graph
{
    #define N 501
    #define M 100001
    
    int tot;
    int front[N],to[M<<1],nxt[M<<1],val[M<<1],from[M<<1];
    
    LL DIS[N];
    
    bool vis[N];
    
    struct node
    {
        LL dis;
        int id;
        bool operator < (node p) const
        {
            return dis>p.dis;
        }
    }cur,nt;
    
    void add(int u,int v,int w)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w; from[tot]=u;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=w; from[tot]=v;
    }
    
    void dijkstra(int n)
    {
        memset(DIS,1,sizeof(DIS));
        DIS[n]=0;
        priority_queue<node>q;
        cur.dis=0;
        cur.id=n;
        q.push(cur);
        while(!q.empty())
        {
            cur=q.top();
            q.pop();
            if(DIS[cur.id]!=cur.dis) continue;
            for(int i=front[cur.id];i;i=nxt[i])
            {
                if(DIS[to[i]]>DIS[cur.id]+val[i])
                {
                    DIS[to[i]]=DIS[cur.id]+val[i];
                    nt.dis=DIS[to[i]];
                    nt.id=to[i];
                    q.push(nt);
                }
            }
        }
    }
    
    void build()
    {
        Net.tot=1;
        for(int i=1;i<=tot;++i)
        {
            if(DIS[from[i]]-val[i]==DIS[to[i]]) 
            {
                //cout<<from[i]<<' '<<to[i]<<'\n';
                Net.add(from[i]<<1|1,to[i]<<1,inf);
            }
        }
    }
    
    #undef N
    #undef M
}G;

int main()
{
    //freopen("cqoi15_network.in","r",stdin);
    //freopen("cqoi15_network.out","w",stdout);
    int n,m;
    read(n); read(m);
    int u,v,w;
    while(m--)
    {
        read(u); read(v); read(w);
        G.add(u,v,w);
    }
    for(int i=1;i<=n;++i) read(Net.cap[i]);
    G.dijkstra(n);
    //cout<<G.DIS[1]<<'\n';
    G.build();
    Net.build(n);
    cout<<Net.isap();
}

 

3931: [CQOI2015]网络吞吐量

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 2094  Solved: 873
[Submit][Status][Discuss]

Description

 路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点。网络中实现路由转发的硬件设备称为路由器。为了使数据包最快的到达目的地,路由器需要选择最优的路径转发数据包。例如在常用的路由算法OSPF(开放式最短路径优先)中,路由器会使用经典的Dijkstra算法计算最短路径,然后尽量沿最短路径转发数据包。现在,若已知一个计算机网络中各路由器间的连接情况,以及各个路由器的最大吞吐量(即每秒能转发的数据包数量),假设所有数据包一定沿最短路径转发,试计算从路由器1到路由器n的网络的最大吞吐量。计算中忽略转发及传输的时间开销,不考虑链路的带宽限制,即认为数据包可以瞬间通过网络。路由器1到路由器n作为起点和终点,自身的吞吐量不用考虑,网络上也不存在将1和n直接相连的链路。

 

Input

输入文件第一行包含两个空格分开的正整数n和m,分别表示路由器数量和链路的数量。网络中的路由器使用1到n编号。接下来m行,每行包含三个空格分开的正整数a、b和d,表示从路由器a到路由器b存在一条距离为d的双向链路。 接下来n行,每行包含一个正整数c,分别给出每一个路由器的吞吐量。

 

Output

输出一个整数,为题目所求吞吐量。

 

Sample Input

7 10
1 2 2
1 5 2
2 4 1
2 3 3
3 7 1
4 5 4
4 3 1
4 6 1
5 6 2
6 7 1
1
100
20
50
20
60
1

Sample Output

70

HINT

 

 对于100%的数据,n≤500,m≤100000,d,c≤10^9

posted @ 2017-12-14 21:03  TRTTG  阅读(246)  评论(0编辑  收藏  举报