2019杭電多校暑假訓練_第一場_E_Path

題目大意:
一張圖裏有n個節點,m條邊,要讓我們去割掉一些邊,讓從1到n的距離增大。

解題思路:
首先跑一遍從1 - n 的最短路,然後得到d1數組,然後根據性質:d[v] == d[u] + w[i], 這個性質得到最短路的邊,然後重新構建一個最短路徑的圖,然後再求這張新圖的最小割。

AC代碼:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <map>

using namespace std;

typedef long long LL;
typedef pair<int, int> 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<PII, vector<PII>, greater<PII> > 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<int> 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. == 不要寫成了 = !!!(坑了我幾個小時,在這個地方)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章