POJ 2175 Floyd-Warshall

题意

传送门 POJ 2175

题解

流量过大,最小费用流跪了。题意只要求答案优于当前方案即可,用 Floyd-Warshall 在增广路上求负圈,沿着负圈增广即可得到费用更小的流。实现上考虑到所提供方案城市人数安排一一对应,则源点到城市的边满流,求负圈时源点可不考虑在内。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <queue>
#include <vector>
#define min(a,b)    (((a) < (b)) ? (a) : (b))
#define max(a,b)    (((a) > (b)) ? (a) : (b))
#define abs(x)    ((x) < 0 ? -(x) : (x))
#define INF 0x3f3f3f3f
#define delta 0.85
#define eps 1e-5
#define PI 3.14159265358979323846
using namespace std;

#define MAX_N 100
#define MAX_M 100
int N, M;
int X[MAX_N], Y[MAX_N], B[MAX_N];
int P[MAX_N], Q[MAX_N], C[MAX_N];
int E[MAX_N][MAX_M];

#define MAX_V 202
int dist[MAX_V][MAX_V];
int prev[MAX_V][MAX_V];
bool used[MAX_V];

void solve(){
	memset(dist, 0x3f, sizeof(dist));
	int t = N + M, V = t + 1;
	// 建立邻接矩阵,为所有增广路赋对应权值
	for(int j = 0; j < M; j++){
		int s = 0;
		for(int i = 0; i < N; i++){
			int d = abs(X[i] - P[j]) + abs(Y[i] - Q[j]) + 1;
			s += E[i][j];
			if(E[i][j] > 0) dist[N + j][i] = -d;
			if(E[i][j] < min(B[i], C[j])) dist[i][N + j] = d;
		}
		if(s > 0) dist[t][N + j] = 0;
		if(s < C[j]) dist[N + j][t] = 0;
	}
	for(int i = 0; i < V; i++){
		for(int j = 0; j < V; j++){
			prev[i][j] = i;
		}
	}
	// Floyd-Warshall
	for(int k = 0; k < V; k++){
		for(int i = 0; i < V; i++){
			for(int j = 0; j < V; j++){
				if(dist[i][j] > dist[i][k] + dist[k][j]){
					dist[i][j] = dist[i][k] + dist[k][j];
					prev[i][j] = prev[k][j];
					if(i == j && dist[i][j] < 0){
						// 找到负圈
						memset(used, 0, sizeof(used));
						for(int v = i; !used[v]; v = prev[i][v]){
							used[v] = 1;
							if(v != t && prev[i][v] != t){
								if(v >= N) ++E[prev[i][v]][v - N];
								else --E[v][prev[i][v] - N];
							}
						}
						printf("SUBOPTIMAL\n");
						for(int i = 0; i < N; i++){
							for(int j = 0; j < M; j++){
								printf("%d%c", E[i][j], j == M - 1 ? '\n' : ' ');
							}
						}
						return;
					}
				}
			}
		}
	}
	printf("OPTIMAL\n");
}

int main(){
	while(~scanf("%d%d", &N, &M)){
		for(int i = 0; i < N; i++) scanf("%d%d%d", X + i, Y + i, B + i);
		for(int i = 0; i < M; i++) scanf("%d%d%d", P + i, Q + i, C + i);
		for(int i = 0; i < N; i++){
			for(int j = 0; j < M; j++){
				scanf("%d", &E[i][j]);
			}
		}
		solve();
	}
	return 0;
}
发布了110 篇原创文章 · 获赞 1 · 访问量 2051

猜你喜欢

转载自blog.csdn.net/neweryyy/article/details/105394788