- 题意: 无向图的网络流
- 思路: 无向图在加边时,要加两条方向相反流量相同的边,不同于有向图的流量为0的反悔边. 这题的数据范围比较大,容易T
巨巨能跑0ms,说不定是专门卡dinic.借此来学习一下dinic的几个优化.
- 多路增广: 其实这种优化已经成了正常的写法,说不上是优化了感觉,在dfs时跑完当前点u的一个边的流量后没有直接返回,而是修改流量接着跑u的其他边
- 当前弧: 在当前分层图中,每次跑到点u,都从上一次u跑出的最后一条边开始枚举,避免重复访问跑过的边
- 炸点: 当前点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; }
来源:博客园
作者:新新人类
链接:https://www.cnblogs.com/xxrlz/p/11421285.html