HDU 4280 Island Transport(最大流)

题意:给定一些小岛的坐标,要求从最东边到最西边。问最大流量是多少。

解法:裸的最大流。本题确实卡了一下dinic,我用普通的读入挂跑了9s,用fread跑了7400ms。但是看了看别人isap啥都没加跑了5s。

有的人用dinic超时是因为板子问题。有的板子里面bfs是从s开始到t,然后dfs也是s到t,这样是不够高效的。

因为如果一个图从s开始有很多无用的边根本就到达不了t那种,就会使得dfs的时候递归层数增多,效率变低。

我们想办法尽量剪掉这些枝,折中一点的办法就是bfs的时候应该从t到s,然后dfs的时候从s到t,这样无用的边就尽量少访问了。

代码如下:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
const int maxn = 1e5 + 5;
const int maxm = 2e5 + 5;
const int INF = 0x3f3f3f3f;

const int maxsize = 5e7;
char buf[maxsize];
int bufpos;
void init_read() {
    buf[fread(buf, 1, maxsize, stdin)] = '\0';
    bufpos = 0;
}
inline int read() {
    int x = 0, f = 0;
    for (; buf[bufpos] < '0' || buf[bufpos] > '9'; bufpos++)
    	if(buf[bufpos] == '-')
    		f = 1;
    for (; buf[bufpos] >= '0' && buf[bufpos] <= '9'; bufpos++) {
        x = x * 10 + buf[bufpos] - '0';
    }
    return f ? -x : x; 
}

int head[maxn],cur[maxn],nx[maxm<<1],to[maxm<<1],flow[maxm<<1],ppp=0;
struct Dinic {
	int dis[maxn];
	int s, t;
	int ans;
	
	void init() {
		memset(head, -1, sizeof(head));
		ppp = 0;
	}
	
	void AddEdge(int u, int v, int c) {
		to[ppp]=v;flow[ppp]=c;nx[ppp]=head[u];head[u]=ppp++;swap(u,v);
		to[ppp]=v;flow[ppp]=0;nx[ppp]=head[u];head[u]=ppp++;
	}
	
	bool BFS() {
		memset(dis, -1, sizeof(dis));
		dis[t] = 1; 
		queue<int> Q;
		Q.push(t);
		while(!Q.empty()) {
			int x = Q.front();
			Q.pop();
			for(int i = head[x]; ~i; i = nx[i]) {
				if(flow[i^1] && dis[to[i]] == -1) {
					dis[to[i]] = dis[x] + 1;
					Q.push(to[i]);
				}
			}
		}
		return dis[s] != -1;
	}
	
	int DFS(int x, int maxflow) {
		if(x == t || !maxflow){
			ans += maxflow;
			return maxflow;
		}
		int ret = 0, f;
		for(int &i = cur[x]; ~i; i = nx[i]) {
			if(dis[to[i]] == dis[x] - 1 && (f = DFS(to[i], min(maxflow, flow[i])))) {
				ret += f;
				flow[i] -= f;
				flow[i^1] += f;
				maxflow -= f;
				if(!maxflow)
					break;
			}
		}
		return ret;
	}
	
	int solve(int source, int tank) {
		s = source;
		t = tank;
		ans = 0;
		while(BFS()) {
//			cout << ans << ' ' << dis[s] << '\n';
			memcpy(cur, head, sizeof(cur));
			DFS(s, INF);
		}
		return ans;
	}
}dinic;

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif
	init_read();
	int T = read();
	while(T--) {
		int n=read(), m=read(), l = INF, r = -INF, s, t;
		dinic.init();
		for(int i = 1, x, y; i <= n; i++) {
			x = read(), y = read();
//			cout << x << ' ' << y << '\n'; 
			if(x < l) {
				s = i;
				l = x;
			}
			if(x > r) {
				t = i;
				r = x;
			}
		}
		while(m--) {
			int u = read(),v = read(),c = read();
			dinic.AddEdge(u, v, c);
			dinic.AddEdge(v, u, c);
		}
		printf("%d\n", dinic.solve(s,t));
	} 
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值