Poj2175(费用流,负环消圈)

来源:互联网 发布:2015最红网络歌曲 编辑:程序博客网 时间:2024/04/30 22:12

挺好的题 充分利用了spfa 判断最费用流是否最优的充分必要条件是——图中是否存在负环  如果存在说明最费用流最优否则相反

/** this code is made by LinMeiChen* Problem:* Type of Problem: 最小费用流* Thinking: 先按照市政府的方发建图判断是否可行,如果不行这用自己的方法* Feeling:*/#include<iostream>#include<algorithm>#include<stdlib.h>#include<string.h>#include<stdio.h>#include<math.h>#include<string>#include<vector>#include<queue>#include<list>using namespace std;typedef long long lld;typedef unsigned int ud;#define oo 0x3f3f3f3f#define eatline() char chch;while((chch=getchar())!='\n')continue;#define MemsetMax(a) memset(a,0x3f,sizeof a)#define MemsetZero(a) memset(a,0,sizeof a)#define MemsetMin(a) memset(a,-1,sizeof a)#define MemsetFalse(a) MemsetZero(a)#define PQ priority_queue#define Q queue#define maxn 250#define maxm 500000struct Edge{int v, f, c, next;}E[maxm];int tol, n, m, cnt[maxn];int head[maxn], pre[maxn];int dis[maxn], mark[maxn];int q[maxn*maxm], front, rear;int line[maxn][maxn];int sum[maxn];struct Node{int x, y, c;};Node bg[maxn], home[maxn];int getCost(Node& n1, Node& n2){return abs(n1.x - n2.x) + abs(n1.y - n2.y) + 1;}int Spfa(int s, int t){memset(pre, -1, sizeof pre);memset(mark, 0, sizeof mark);memset(cnt, 0, sizeof cnt);fill(dis, dis + maxn, oo);dis[t] = 0;mark[t] = 1;cnt[t]++;front = rear = 0;q[rear++] = t;while (front < rear){int u = q[front++];mark[u] = 0;for (int i = head[u]; i != -1; i = E[i].next){int v = E[i].v;if (E[i].f>0 && dis[v] > dis[u] + E[i].c){dis[v] = dis[u] + E[i].c;pre[v] = u;if (!mark[v]){q[rear++] = v;mark[v] = 1;if (++cnt[v] > n + m + 2)return v;}}}}return -1;}void add_edge(int u, int v, int f, int c){E[tol].v = v;E[tol].f = f;E[tol].c = c;E[tol].next = head[u];head[u] = tol++;}void Build(int s, int t){memset(head, -1, sizeof head);tol = 0;for (int i = 1; i <= n; i++){add_edge(s, i, 0, 0);add_edge(i, s, bg[i].c, 0);}for (int i = 1; i <= m; i++){add_edge(i + n, t, home[i].c - sum[i], 0);add_edge(t, i + n, sum[i], 0);}for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++){add_edge(i, j + n, oo - line[i][j], getCost(bg[i],home[j]));add_edge(j + n, i, line[i][j], -getCost(bg[i], home[j]));}}int main(){int s, t;while (scanf("%d%d", &n, &m) != EOF){s = n + m + 1;t = s + 1;for (int i = 1; i <= n; i++){scanf("%d%d%d", &bg[i].x, &bg[i].y, &bg[i].c);}for (int i = 1; i <= m; i++){scanf("%d%d%d", &home[i].x, &home[i].y, &home[i].c);}memset(sum, 0, sizeof sum);for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++){scanf("%d", &line[i][j]);sum[j] += line[i][j];}Build(s, t);int ans = Spfa(s, t);if (ans == -1)printf("OPTIMAL\n");else{printf("SUBOPTIMAL\n");memset(mark, 0, sizeof mark);int a = ans, b;while (true){if (!mark[a]){mark[a] = 1;a = pre[a];}else{b = a;break;}}do{int u = pre[a];int v = a;if (u <= n&&v > n)line[u][v - n]++;if (v <= n&&u > n)line[v][u - n]--;a = pre[a];} while (a != b);for (int i = 1; i <= n; i++){for (int j = 1; j < m; j++){printf("%d ", line[i][j]);}printf("%d\n", line[i][m]);}}}return 0;}/*3 4-3 3 5-2 -2 62 2 5-1 1 31 1 4-2 -2 70 -1 33 1 1 00 0 6 00 3 0 23 4-3 3 5-2 -2 62 2 5-1 1 31 1 4-2 -2 70 -1 33 0 1 10 0 6 00 4 0 1*/
memset(mark, 0, sizeof mark);int a = ans, b;while (true){if (!mark[a]){mark[a] = 1;a = pre[a];}else{b = a;break;}}do{int u = pre[a];int v = a;if (u <= n&&v > n)line[u][v - n]++;if (v <= n&&u > n)line[v][u - n]--;a = pre[a];} while (a != b);注意:返回的v不一定在环里面这段代码是找出这个环,并且见环对应的变做变化,正向边++,反向边--代码的构建参与网络图void Build(int s, int t){memset(head, -1, sizeof head);tol = 0;for (int i = 1; i <= n; i++){add_edge(s, i, 0, 0);add_edge(i, s, bg[i].c, 0);}for (int i = 1; i <= m; i++){add_edge(i + n, t, home[i].c - sum[i], 0);add_edge(t, i + n, sum[i], 0);}for (int i = 1; i <= n; i++)for (int j = 1; j <= m; j++){add_edge(i, j + n, oo - line[i][j], getCost(bg[i],home[j]));add_edge(j + n, i, line[i][j], -getCost(bg[i], home[j]));}}体会下。。。

0 0