消负权法。
最小费用最大流的充要条件是,增广路没有负圈。
所以这道题就是找到一个负圈,然后绕着路自己增广一周就好了。
注意这里用的是,floyd算法去寻找负圈,要用类似链式储存的方式,来进行保存前面的节点。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
//#include<regex>
#include<cstdio>
#define up(i,a,b)  for(int i=a;i<b;i++)
#define dw(i,a,b)  for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int, int> pir;
int n, m;
int model[205][205];
bool used[305];
int g[305][305];
int prevv[305][305];
int xi[105], yi[105];
int xj[105], yj[105];
int wi[105],wj[105];
void solve()
{
	int m1 = n + m + 1;
	up(i,0,m1)fill(g[i],g[i]+m1,1e9);
	up(j, 0, m)
	{
		int sum = 0;
		up(i, 0, n)
		{
			int dist = fabs(xi[i] - xj[j]) + fabs(yi[i] - yj[j]) + 1;
			g[i][n + j] = dist;
			if(model[i][j]>0)//有流量,才会有反向费用
				g[n + j][i] = -dist;
			sum += model[i][j];//每个隧道的总人数
		}
		if (sum > 0)g[n + m][n + j] = 0;//有流量,那么汇点到节点就有反向边
		if (sum < wj[j])g[n + j][n + m] = 0;//没有满流,有正向边
	}
	up(i, 0, m1)
		up(j, 0, m1)
			prevv[i][j] = i;//预处理,每个点的头结点都是自己,
	up(k, 0, m1)	//要先从k开始
	{
		up(i, 0, m1)
		{
			up(j, 0, m1)
			{
				if (g[i][j] > g[i][k] + g[k][j])//松弛条件
				{
					g[i][j] = g[i][k] + g[k][j];
					prevv[i][j] = prevv[k][j];//链式储存
					if (i == j&&g[i][j]<0)//如果此时形成环了
					{
						memset(used, false, sizeof(used));
						for (int v = i; !used[v]; v = prevv[i][v])
						{
							used[v] = true;
							if (v >= n)
								model[prevv[i][v]][v - n]++;
							else model[v][prevv[i][v] - n]--;
						}//负权增广
						printf("SUBOPTIMAL\n");
						up(x,0,n)
						{
							up(y,0,m)
							{
								printf("%d%c", model[x][y], y + 1 != m ? ' ' : '\n');
							}
						}
						return;
					}
				}
			}

		}
	}
	cout << "OPTIMAL\n" << endl;
}
int main()
{
	cin >> n >> m;
	up(i, 0, n)
	{
		cin >> xi[i] >> yi[i] >> wi[i];
	}
	up(i, 0, m)
	{
		cin >> xj[i] >> yj[i] >> wj[i];
	}
	up(i, 0, n)

	{
		up(j, 0, m)
		{
			cin >> model[i][j];
		}
	}
	solve();
	return 0;
}
Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐