2019杭电多校暑假训练_第一场

题目大意:
一张图里有n个节点,m条边,要让我们去割掉一些边,让从1到n的距离增大。

解题思路:
首先跑一遍从1 - n 的最短路,然后得到d1数组,然后根据性质:d[v] == d[u] + w[i], 这个性质得到最短路的边,然后重新构建一个最短路径的图,然后再求这张新图的最小割。

AC代码:

#include 
#include 
#include 
#include 
#include 

using namespace std;

typedef long long LL;
typedef pair PII;

const int maxn = 1e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;

int n, m, s, t;
int h[maxn], e[maxn * 2], ne[maxn * 2], idx;
int d[maxn];
LL d1[maxn], w[maxn * 2];
LL ans, maxflow;
bool vis[maxn];

//构图
int ncu_x[maxn], ncu_y[maxn];
LL ncu_w[maxn];
int permt;
int h1[maxn], e1[maxn * 2], ne1[maxn * 2], idx1;
LL w1[maxn * 2];

inline void add(int a, int b, int c) {
	e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++;
}

inline void add1(int a, int b, LL c) {
	e1[idx1] = b, w1[idx1] = c, ne1[idx1] = h1[a], h1[a] = idx1 ++;
	e1[idx1] = a, w1[idx1] = 0, ne1[idx1] = h1[b], h1[b] = idx1 ++;
}

inline void dijkstra(void) {
	memset(vis, false, sizeof vis);
	memset(d1, 0x3f, sizeof d1);
	priority_queue, greater > q;
	
	d1[1] = 0;
	q.push({0, 1});
	
	while(q.size()) {
		PII tmp = q.top(); q.pop(); 
		int u = tmp.second, du = tmp.first;
		vis[u] = true;
		
		for(int i = h[u]; i != -1; i = ne[i]) {
			int v = e[i];
			if(vis[v]) continue;
			if(d1[v] > d1[u] + w[i]) {
				d1[v] = d1[u] + w[i];
				q.push({d1[v], v});
			}
		}
	}
}

inline bool bfs(void) {
	queue q;
	while(q.size()) q.pop();
	memset(d, 0, sizeof d);
	
	q.push(s), d[s] = 1;
	
	while(q.size()) {
		int u = q.front(); q.pop(); 
		
		for(int i = h1[u]; i != -1; i = ne1[i]) {
			int v = e1[i];
			if(w1[i] && !d[v]) {
				q.push(v);
				d[v] = d[u] + 1;
			}
		}
	}
	
	if(d[t] == 0) return false;
	return true;
}

inline LL dinic(int u, LL flow) {
	if(u == t) return flow;
	
	for(int i = h1[u]; i != -1; i = ne1[i]) {
		int v = e1[i];
		if(d[v] == d[u] + 1 && w1[i]) {
			int k = dinic(v, min(flow, w1[i]));
			if(k) {
				w1[i] -= k;
				w1[i ^ 1] += k;
				return k;
			} else d[v] = 0;
		}
	}
	
	return 0;
}

int main(void) {
	freopen("in.txt", "r", stdin);
	
	int T;
	scanf("%d", &T);
	while(T --) {
		scanf("%d%d", &n, &m);
		memset(h, -1, sizeof h);
		idx = 0;
		for(int i = 1; i <= m; i ++) {
			int a, b, c;
			scanf("%d%d%d", &a, &b, &c);
			add(a, b, (LL)c);
		}
		
		//找最短路 
		dijkstra();
		if(d1[n] == inf) printf("0\n");
		else {
			
			//重新构图	
			memset(h1, -1, sizeof h1), idx1 = 0;
			for(int u = 1; u <= n; u ++)
				for(int i = h[u]; i != -1; i = ne[i]) {
					int v = e[i];
					if(d1[v] == d1[u] + w[i]) 
						add1(u, v, w[i]);		
				}
				
			//找到最小割 
			s = 1, t = n;
			LL flow; 
			maxflow = 0;
			while(bfs()) 
			while(flow = dinic(1, inf)) maxflow += flow;
				
			printf("%lld\n", maxflow);
		}
	}
	
	fclose(stdin);
	return 0;
}

注意点:
1.注意数组的大小不要开小了
2.当我们重新构图的时候可以重新开辟新的数组空间进行重新构图,没有必要去重新初始化原图(我最开始是重新初始化原图,怎么改也改不对)
3. == 不要写成了 = !!!(坑了我几个小时,在这个地方)
4. == 不要写成了 = !!!(坑了我几个小时,在这个地方)
5. == 不要写成了 = !!!(坑了我几个小时,在这个地方)

你可能感兴趣的:(2019杭电训练)