最短路,网络流(HDU 5294,Tricks Device)

来源:互联网 发布:java 全栈开发框架 编辑:程序博客网 时间:2024/06/10 02:08

最短路+网络流算是很经典的套路了。

但是自己还是一直WA得不明所以。

原因是自己对edmondskarp算法的不理解。

首先,这道题的图是无向图,这点从题干中可以很容易的得到。

跑完Dijkstra后,我们得到了一个最短路树。

最早听说最短路树的概念是在大白书P330上。

意思是Dijkstra算法跑完以后会得到一个p数组,表示s到v的最短路径中v的前一个节点。

显然p数组能表示一个以s为根的树,如果想要从原点出发沿着最短路走到任意其他点,只要顺着树上的边走即可。

但是,最短路不唯一,最短路树对每一个节点只标出了一个最短路,如果非要标记出所有最短路的话,树形结构肯定是不够用的。

事实上,对于没有负环的图,所有可能的最短路会形成一个有向无环图。

我们也不需要弄一个什么结构去记录它,d数组就是一个最好的记录。

我们只需要沿着d[e.to]==d[e.from]+e.dist的方向走就ok了。

虽然有时候会走到死胡同,从而导致多了一些不必要的搜索,但是这不会慢太多,而且也没什么更简单实用的方法了。

我们就利用d数组的记录去建立一个网络流,网络流的边是有向边,每个有向边都有一个正向弧和一个反向弧。反向弧是为了反向增广,这和再加一条反向的有向边是不一样的。

我们应该利用最短路的有向无环图去建立一个有向网络流。如果建成无向网络流那就错了。


总结一下:

1、对原图建立无向图。

2、对原图跑Dijkstra得到最短路的有向无环图。

3、在这个有向无环图上跑bfs得到通过边数最少的最短路。

4、对这个有向无环图建立有向网络流,跑Edmondskarp得到最大流或最小割。


代码

#include<bits/stdc++.h>using namespace std;const int maxn = 2010;const int inf = 0x3f3f3f3f;struct Edge{    int from,to,dist,cap,flow;};struct HeapNode{    int d,u;    bool operator < (const HeapNode& rhs) const    {        return d>rhs.d;    }};struct Dijkstra_EdmondsKarp{    int n,m;    vector<Edge>edges;    vector<int>G[maxn];    int d[maxn];    int done[maxn];    int p[maxn];    int a[maxn];    int dd[maxn];    void init(int n)    {        this->n=n;        for(int i=1;i<=n;i++) G[i].clear();        edges.clear();    }    void Add_Edge(int from,int to,int dist)    {        edges.push_back((Edge){from,to,dist,1,0});        edges.push_back((Edge){to,from,dist,0,0});        m=edges.size();        G[from].push_back(m-2);        G[to].push_back(m-1);    }    void dijkstra(int s)    {        for(int i=1;i<=n;i++)        {            d[i]=inf;            done[i]=0;        }        d[s]=0;        priority_queue<HeapNode>q;        q.push((HeapNode){0,s});        while(!q.empty())        {            HeapNode now=q.top();            q.pop();            int u=now.u;            if(done[u]) continue;            done[u]=1;            for(int i=0;i<(int)G[u].size();i++)            {                Edge&e = edges[G[u][i]];                if(e.cap==0) continue;                if(d[e.to]>d[e.from]+e.dist)                {                    d[e.to]=d[e.from]+e.dist;                    q.push((HeapNode){d[e.to],e.to});                }            }        }    }    int Maxflow(int s,int t)    {        int flow=0;        while(1)        {            for(int i=1;i<=n;i++) a[i]=0;            a[s]=inf;            queue<int>q;            q.push(s);            while(!q.empty())            {                int u=q.front();                q.pop();                for(int i=0;i<(int)G[u].size();i++)                {                    Edge& e= edges[G[u][i]];                    bool f=false;                    if(d[e.to]-d[e.from]==e.dist&&e.cap==1) f=true;                    if(d[e.from]-d[e.to]==e.dist&&e.cap==0) f=true;                    if(!f) continue;                    if(!a[e.to]&&e.cap>e.flow)                    {                        a[e.to]=min(a[e.from],e.cap-e.flow);                        p[e.to]=G[u][i];                        q.push(e.to);                    }                }                if(a[t]) break;            }            if(!a[t]) break;            for(int u=t;u!=s;u=edges[p[u]].from)            {                edges[p[u]].flow+=a[t];                edges[p[u]^1].flow-=a[t];            }            flow+=a[t];        }        return flow;    }    int bfs(int s,int t)    {        if(s==t) return 0;        for(int i=1;i<=n;i++) dd[i]=0;        queue<int>q;        q.push(1);        while(!q.empty())        {            int u=q.front();            q.pop();            for(int i=0;i<(int)G[u].size();i++)            {                Edge& e= edges[G[u][i]];                if(d[e.to]-d[e.from]==e.dist&&!dd[e.to])                {                    dd[e.to]=dd[e.from]+1;                    if(e.to==t) return dd[e.to];                    q.push(e.to);                }            }        }        return m/4;    }}DIJEDK;int N,M;void solve(){    int u,v,w;    DIJEDK.init(N);    for(int i=1;i<=M;i++)    {        scanf("%d %d %d",&u,&v,&w);        DIJEDK.Add_Edge(u,v,w);        DIJEDK.Add_Edge(v,u,w);    }    DIJEDK.dijkstra(1);    printf("%d ",DIJEDK.Maxflow(1,N));    printf("%d\n",M-DIJEDK.bfs(1,N));}int main(){    while(scanf("%d %d",&N,&M)==2) solve();    return 0;}


0 0
原创粉丝点击