http://acm.hdu.edu.cn/showproblem.php?pid=5294
SPFA:
Bellman_Ford的队列优化算法
无法处理带负环的图
复杂度O(kE) k <= 2
Dinic 算法
O(n^2*m)
先BFS找到层次图,如果在这个层次图里面无法再访问到n说明找不到增广路
层次图就相当于可以进行增广的图,但是不知道增广到什么程度
相当于EK算法中从0遍历到n
然后就DFS找增广路
当权值为1时 最大流= 最小割
可以当做模板
/************************************************ * Author :Powatr * Created Time :2015-8-26 13:04:46 * File Name :spfa+dinic.cpp ************************************************/ #include <cstdio> #include <algorithm> #include <iostream> #include <sstream> #include <cstring> #include <cmath> #include <string> #include <vector> #include <queue> #include <deque> #include <stack> #include <list> #include <map> #include <set> #include <bitset> #include <cstdlib> #include <ctime> using namespace std; #define lson l, mid, rt << 1 #define rson mid + 1, r, rt << 1 | 1 typedef long long ll; const int MAXN = 2e3 + 10; const int INF = 0x3f3f3f3f; const int MOD = 1e9 + 7; int cnt[MAXN]; int it[MAXN]; int d[MAXN]; bool vis[MAXN]; int check[MAXN]; struct edge{ int v, w; }; struct edge1{ int v, rev, dir; }; queue<int> q; vector<edge> G[MAXN]; vector<edge1> F[MAXN]; int n, m; void add_edge(int u, int v) { int len1 = F[v].size(), len2 = F[u].size(); F[u].push_back((edge1){v, len1, 1});//因为开了结构体F[i][j]不再是下一个点的u,所以要记录下位置 F[v].push_back((edge1){u, len2 - 1, 0}); } void SPFA() { memset(vis, false, sizeof(vis)); vis[1] = true; for(int i = 1; i <= n; i++){ d[i] = cnt[i] = INF; } d[1] = cnt[1] = 0; while(!q.empty()) q.pop(); q.push(1); while(!q.empty()){ int u = q.front(); q.pop(); vis[u] = false;//入队的点开始不能确定是最优的 for(int i = 0; i < G[u].size(); i++){ int v = G[u][i].v, w = G[u][i].w; if(d[v] == d[u] + w) { cnt[v] = min(cnt[v], cnt[u] + 1); } if(d[v] > d[u] + w){ d[v] = d[u] + w; cnt[v] = cnt[u] + 1; if(!vis[v]){ vis[v] = true; q.push(v); } } } } } void build_gragh() {//对于最短路再建一张图 for(int i = 1; i <= n; i++){ for(int j = 0 ; j < G[i].size(); j++){ edge &e = G[i][j]; if(d[i] + e.w == d[e.v]){ add_edge(i, e.v); } } } } int BFS() {//得带层次图 memset(check, -1, sizeof(check)); while(!q.empty()) q.pop(); check[1] = 0; q.push(1); while(!q.empty()){ int u = q.front(); q.pop(); for(int i = 0 ;i < F[u].size(); i++){ edge1 &e = F[u][i]; if(e.dir > 0 && check[e.v] < 0){//正向 check[e.v] = check[u] + 1; q.push(e.v); } } } if(check[n] != -1) return 1; return 0; } int DFS(int u, int f) {//增广 if(u == n) return f; for(int i = it[u]; i < F[u].size(); i++){//增广路优化,如果访问过下一个直接跳过来 it[u] = i; edge1 &e = F[u][i]; if(e.dir > 0 && check[e.v] == check[u] + 1 ){ int d= DFS(e.v, min(f, e.dir)); if(d > 0){ e.dir -= d; F[e.v][e.rev].dir += d;//得到反向边 return d; } } } return 0; } int Dinic() { int flow = 0, f; while(BFS()){//对于一个层次图能进行多次增广 memset(it, 0, sizeof(it)); while((f = DFS(1,INF)) > 0){ flow += f; } } return flow; } int main(){ while(~scanf("%d%d", &n, &m)){ int u, v, w; for(int i = 1; i <= n; i++){ G[i].clear(); F[i].clear(); } for(int i = 1; i <= m; i++){ scanf("%d%d%d", &u, &v, &w); G[u].push_back((edge){v, w}); G[v].push_back((edge){u, w}); } SPFA(); build_gragh(); int ans = Dinic(); printf("%d %d ", ans, m - cnt[n]); } return 0; }