Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 53153 | Accepted: 20238 |
Description
Input
Output
Sample Input
5 4 1 2 40 1 4 20 2 4 20 2 3 30 3 4 10
Sample Output
50
1、EK
思路:
网络流EK算法入门模板题;
资料 http://blog.sina.com.cn/s/blog_6cf509db0100uy5n.html
代码:
#include <stdio.h> #include <string.h> #include <queue> #define INF 0xfffffff #define N 220 using namespace std; int map[N][N]; bool vis[N]; // bfs 时标记,避免走回路 int pre[N]; // 父节点 bool bfs(int start, int num) { memset(pre, -1, sizeof(pre)); // 父节点初始化成-1 memset(vis, 0, sizeof(vis)); queue<int>q; pre[start] = start; // 起点的父节点是本身 vis[start] = 1; q.push(start); int cur; while(!q.empty()){ cur = q.front(); q.pop(); for(int i = 1; i <= num; i ++){ if(map[cur][i] > 0 && !vis[i]){ // 有关系,并且未曾访问 pre[i] = cur; vis[i] = 1; if(i == num) // 到达终点 return 1; q.push(i); } } } return 0; } int EK(int start, int num) { int ans = 0, min_w; while( bfs(start, num) ){ min_w = INF; for(int i = num; i != start; i = pre[i]){ // 寻找最小边权,(逆向,找父节点) min_w = min_w < map[pre[i]][i] ? min_w : map[pre[i]][i]; } for(int i = num; i != start; i = pre[i]){ // 更新边权,建立反向边 map[pre[i]][i] -= min_w; map[i][pre[i]] += min_w; } ans += min_w; } return ans; } int main() { int n, m; int start, end, p, ans; while(scanf("%d%d", &m, &n) != EOF){ memset(map, 0, sizeof(map)); for(int i = 0; i < m; i ++){ scanf("%d%d%d", &start, &end, &p); map[start][end] += p; // 注意,可能有重边 } ans = EK(1, n); printf("%d\n", ans); } return 0; }
思路:
bfs时每一步对原图进行分层,然后用DFS求增广路;
代码:
#include <stdio.h> #include <string.h> #include <queue> #define INF 0x7fffffff #define N 220 #define min(a, b) a < b ? a : b using namespace std; int level[N]; // 用于分层 int map[N][N]; int start, end; bool bfs() { queue<int>q; q.push(start); memset(level, 0, sizeof(level)); level[start] = 1; int cur; while(!q.empty()){ cur = q.front(); q.pop(); for(int i = 1; i <= end; i ++){ if(!level[i] && map[cur][i] > 0){ // 条件:之前未被分层,并且两点有边权 level[i] = level[cur] + 1; if(i == end){ // 到达终点 return 1; } q.push(i); } } } return 0; } int dfs(int cur, int cp) { if(cur == end) // 到达终点 return cp; // 返回值是整条路径最小边权值 int t, tmp = cp; for(int i = start; i <= end && tmp; i ++){ if(level[i] == level[cur] + 1 && map[cur][i] > 0){ // 条件:两点之间层数相差1,并且两点之间有边权 t = dfs(i, min(tmp, map[cur][i])); // t接收此条路径最小边权值 map[cur][i] -= t; // 更新边权 map[i][cur] += t; // 建立反向边 tmp -= t; } } return cp - tmp; } int Dinic() { int ans = 0, min_w; while( bfs() ){ // 判断能否走通 while( (min_w = dfs(start, INF)) ){ // 深搜整条路径 ans += min_w; } } return ans; } int main() { start = 1; int ct, x, y, p, ans; while(scanf("%d%d", &ct, &end) != EOF){ memset(map, 0, sizeof(map)); for(int i = 0; i < ct; i ++){ scanf("%d%d%d", &x, &y, &p); map[x][y] += p; } ans = Dinic(); printf("%d\n", ans); } return 0; }