图论测试2 t1 幻想乡的异变 SPFA+最大流

来源:互联网 发布:苹果电脑音频剪辑软件 编辑:程序博客网 时间:2024/05/02 02:52

第一题

考试的时候以为是费用流,于是花了二十几分钟兴致勃勃地打完光荣T掉。。。
后来评讲的时候发现是SPFA+最大流。
对于每个点,先求出1到这个点的最小距离,再求出这个点到n的最小距离,然后枚举每一条边,如果从1到这条边的起始点距离+这条边的边权+这条边的终点到n的距离==1到n的最短路的话,说明这条路就可能出现在1到n的最短路上,流量=1。
最后跑最大流就可以求出最多有多少条满足最短路的路径可以到达终点n。

关于如何求1到各个点与各个点到n的最短路:
从1到n的最短路就用SPFA,从各个点到n可以转化为从n到各个点,所以存反向边,再以n为起点跑一遍SPFA。但由于原图中边是有向的,所以反向边的存在可能会对最短路造成影响:
eg:从1到2有一条200的路,从2到1有一条15的路。
从1到2的最短路是200,但如果不判反向边,最短路就会变成15。所以每次更新时要判一下。

这道题的想法之前学长有讲过一道题很像,就是关于判断这条路在不在最短路上。感觉特别强2333。

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<queue>#define ms(x,y) memset(x,y,sizeof(x))#define ll long long#define INF 233333333using namespace std;const int N = 500010;int n,m;int num=1;int head[N];inline int Min(int a,int b){    return a<b?a:b;}struct node{    int pre,u,v,w,f;}edge[N];void addedge(int from,int to,int w){    num++;    edge[num].pre=head[from];    edge[num].v=to;    edge[num].u=from;    edge[num].f=0;    edge[num].w=w;    head[from]=num;}deque<int> q;ll dis[N][2];bool vis[N];void spfa(int s,int t,int x){    q.push_back(s);dis[s][x]=0;vis[s]=true;    while(!q.empty()){        int u=q.front();q.pop_front();        vis[u]=false;        for(int i=head[u];i;i=edge[i].pre){            int v=edge[i].v;            if((i&1)==x&&dis[v][x]>dis[u][x]+edge[i].w){                dis[v][x]=dis[u][x]+edge[i].w;                if(!vis[v]){                    vis[v]=true;                    if(!q.empty()&&dis[v][x]<dis[q.front()][x])                       q.push_front(v);                    else q.push_back(v);                }            }        }    }}int dist[N];queue<int> q1;bool bfs(){    vis[1]=true;q1.push(1);    while(!q1.empty()){        int u=q1.front();q1.pop();        for(int i=head[u];i;i=edge[i].pre){            int v=edge[i].v;            if(!vis[v]&&edge[i].f){                dist[v]=dist[u]+1;                vis[v]=true;                q1.push(v);            }        }    }    if(vis[n]) return true;    return false;}int dfs(int u,int delta){    if(u==n||delta==0) return delta;    int ans=0;    for(int i=head[u];i&&delta;i=edge[i].pre){        int v=edge[i].v;        if(dist[v]==dist[u]+1&&edge[i].f){            int dd=dfs(v,Min(edge[i].f,delta));            edge[i].f-=dd;            edge[i^1].f+=dd;            ans+=dd;            delta-=dd;        }    }    if(!ans) dist[u]=-1;    return ans;}void zero(){    ms(dist,0);ms(vis,0);    while(!q1.empty()) q1.pop();}int maxflow(){    int ans=0;    while(1){        zero();        if(!bfs()) break;//此处有可能搜不到n。         ans+=dfs(1,INF);    }    return ans;}int main(){    freopen("change.in","r",stdin);    freopen("change.out","w",stdout);    scanf("%d%d",&n,&m);    for(int i=1;i<=m;i++){        int u,v,w;        scanf("%d%d%d",&u,&v,&w);        addedge(u,v,w);        addedge(v,u,w);    }    ms(dis,127);ms(vis,0);    spfa(1,n,0);    ms(vis,0);while(!q.empty()) q.pop_front();    spfa(n,1,1);    for(int i=2;i<=num;i+=2){        int u=edge[i].u,v=edge[i].v;        if(dis[u][0]+edge[i].w+dis[v][1]==dis[n][0]){            edge[i].f=1;        }    }    printf("%d",maxflow());    return 0;}
原创粉丝点击