zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",dinic());
    	}
    	return 0;
    }
    
  • 相关阅读:
    Pentaho
    知识地图
    分享学习笔记本
    2015-7-1 记而随,随而记
    web 导出 csv
    vs2013 密钥
    超时时间已到。超时时间已到,但是尚未从池中获取连接。出现这种情况可能是因为所有池连接均在使用,并且达到了最大池大小。
    如何绘制业务流程图?
    总是保存下拉选项的第一个值
    mac 修改密码后 频繁输入钥匙串问题修复方法
  • 原文地址:https://www.cnblogs.com/xxrlz/p/11421285.html
Copyright © 2011-2022 走看看