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

匿名 (未验证) 提交于 2019-12-02 23:55:01
  • 题意: 无向图的网络流
  • 思路: 无向图在加边时,要加两条方向相反流量相同的边,不同于有向图的流量为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; }
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!