hdu 4280 Island Transport (无向图dinic及优化)

  • 题意: 无向图的网络流
  • 思路: 无向图在加边时,要加两条方向相反流量相同的边,不同于有向图的流量为0的反悔边. 这题的数据范围比较大,容易T巨巨能跑0ms,说不定是专门卡dinic.借此来学习一下dinic的几个优化.
  1. 多路增广: 其实这种优化已经成了正常的写法,说不上是优化了感觉,在dfs时跑完当前点u的一个边的流量后没有直接返回,而是修改流量接着跑u的其他边
  2. 当前弧: 在当前分层图中,每次跑到点u,都从上一次u跑出的最后一条边开始枚举,避免重复访问跑过的边
  3. 炸点: 当前点u流量跑完后,直接将其深度设为-2,不用重复访问没有流量的点.

三种优化全加,queue换成数组模拟,改了好久才过QAQ.

#include<cstdio>
#include<queue>
#include<vector>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<map>
#include<string>
#include<cstring>
#define ll long long
using namespace std;
const int N = 2e5+10;
const int INF = 1e9+7;
typedef pair<int,int> pii;
struct E{
    int u,v,flow,nxt;
    E(){}
    E(int u,int v,int flow,int nxt):u(u),v(v),flow(flow),nxt(nxt){}
}e[N*2];

int n,m,sp,tp,tot;
int head[N],dis[N],cur[N];
void init(){
    tot = 0;    memset(head,-1,sizeof head);
}
void addE(int u,int v,int flow){
    e[tot].u = u; e[tot].v = v; e[tot].flow = flow; e[tot].nxt = head[u]; head[u] = tot++;
    // e[tot].u = v; e[tot].v = u; e[tot].flow = 0; e[tot].nxt = head[v]; head[v] = tot++;
}
int q[N];
int bfs(){
    int qtop=0,qend=0;
    fill(dis+1,dis+1+n,-1);
    dis[sp] = 0;    
    q[qend++] = sp;
    // q.push(sp);
    while(qtop!=qend){
        // int u = q.front();   q.pop();
        int u = q[qtop++];
        for(int i=head[u];~i;i=e[i].nxt){
            int v = e[i].v;
            if(dis[v]==-1 && e[i].flow){
                dis[v] = dis[u]+1;  
                // q.push(v);
                q[qend++] = v;
            }
        }
    }
    return dis[tp]!=-1;
}
int dfs(int u,int flow){
    int res = 0;
    if(u==tp || flow==0)    return flow;
    for(int &i=cur[u];i!=-1;i=e[i].nxt){    // 当前弧, i为cur[u]的引用,i改变cur[u]也会随之改变
        int v = e[i].v;
        if(dis[v]==dis[u]+1 && e[i].flow){
            int d = dfs(v,min(e[i].flow,flow));
            e[i].flow -=d;  
            e[i^1].flow += d;
            res+=d;     // 多路增广,不直接返回一条弧的流量,而是把所有弧都跑完或者没有流量后再返回
            flow -= d;
            if(flow==0) break;  
        }
    }
    if(!res)            // 炸点 使没有流量的点不会被再访问
        dis[u] = -2;
    return res;
}
int dinic(){
    int ans=0,d;
    while(bfs()){
        for(int i=1;i<=n;++i) cur[i] = head[i];
        // while(d=dfs(sp,INF)) 
        ans+=dfs(sp,INF);
    }
    return ans;
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int spp = INF;
        int tpp = -INF;
        scanf("%d%d",&n,&m);
        int u,v,f;
        init();
        for(int i=1;i<=n;++i){
            scanf("%d%d",&u,&v);
            if(u<spp){
                spp = u;    
                sp = i;
            }
            if(u>tpp){
                tpp = u;    
                tp = i;
            }
        }
        for(int i=1;i<=m;++i){
            scanf("%d%d%d",&u,&v,&f);
            addE(u,v,f);
            addE(v,u,f);
        }
        printf("%d\n",dinic());
    }
    return 0;
}

然而最终还是跑8700ms,但我把当前弧去掉后,就能跑6800ms,快了2s... 神奇

#include<cstdio>
#include<queue>
#include<vector>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<map>
#include<string>
#include<cstring>
#define ll long long
using namespace std;
const int N = 1e5+500;
const int INF = 1e9+7;
typedef pair<int,int> pii;
struct E{
    int u,v,flow,nxt;
    E(){}
    E(int u,int v,int flow,int nxt):u(u),v(v),flow(flow),nxt(nxt){}
}e[N*2];

int n,m,sp,tp,tot;
int head[N],dis[N],pre[N],cur[N];
void init(){
    tot = 0;    memset(head,-1,sizeof head);
}
void addE(int u,int v,int flow){
    e[tot].u = u; e[tot].v = v; e[tot].flow = flow; e[tot].nxt = head[u]; head[u] = tot++;
    // e[tot].u = v; e[tot].v = u; e[tot].flow = 0; e[tot].nxt = head[v]; head[v] = tot++;
}
int q[N];
int bfs(){
    int qtop = 0,qend=0;
    // queue<int> q;
    memset(dis,-1,sizeof dis);  
    dis[sp] = 0;    
    q[qend++] = sp;
    // q.push(sp);
    while(qtop!=qend){
        // int u = q.front();   q.pop();
        int u = q[qtop++];
        if(u==tp)   return true;
        for(int i=head[u];~i;i=e[i].nxt){
            int v = e[i].v;
            if(dis[v]==-1 && e[i].flow){
                dis[v] = dis[u]+1;  
                // q.push(v);
                q[qend++] = v;
            }
        }
    }
    return dis[tp]!=-1;
}
int dfs(int u,int flow){
    int res = 0;
    if(u==tp)   return flow;
    for(int i=head[u];i!=-1&&flow;i=e[i].nxt){
        int v = e[i].v;
        if(dis[v]==dis[u]+1 && e[i].flow){
            int d = dfs(v,min(e[i].flow,flow));
            e[i].flow -=d;
            e[i^1].flow += d;
            res+=d;
            flow -= d;
        }
    }
    if(!res)
        dis[u] = -2;
    return res;
}
int dinic(){
    int ans=0;
    while(bfs()){
        ans+=dfs(sp,INF);
    }
    return ans;
}

int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        int spp = INF;
        int tpp = -INF;
        scanf("%d%d",&n,&m);
        int u,v,f;
        init();
        for(int i=1;i<=n;++i){
            scanf("%d%d",&u,&v);
            if(u<spp){
                spp = u;    
                sp = i;
            }
            if(u>tpp){
                tpp = u;    
                tp = i;
            }
        }
        for(int i=1;i<=m;++i){
            scanf("%d%d%d",&u,&v,&f);
            addE(u,v,f);
            addE(v,u,f);
        }
        printf("%d\n",dinic());
    }
    return 0;
}
上一篇:新浪博客地址 http://blog.sina.com.cn/u/2145079955


下一篇:HDU-4280 Island Transport