题解P2294 [HNOI2005] 狡猾的商人

题目传送门https://www.luogu.com.cn/problem/P2294

题目分析

看到这种多元未知数要求一定关系的题目,通常会使用差分约束算法查看是否有解,但注意到本题仅要求相等,这使得我们可以用更简单的方法来判断。设 x_i 是前 i 个月的收入总和,输入告诉我们了 m 个形如 x_i=x_j+w 的信息,其中 j ,  w  分别代表记账区间  [l,r] 中的 l-1 与区间内的总收益,由于真实的账本某个月的收入是一定的,因此如果该账本是真实的,其中输入的信息一定保持一致,即不论通过何种方法运算两个特定月份所赚的钱数,答案总是一致的。设 longDis[i][j] , shortDis[i][j] 分别代表两个月之间按题目信息算出的最大收益与最小收益,如果对于所有可以计算(可以计算只的是 i<j 且存在足够多的关系使得 X_{i}=X_{a1}+w_1,X_{a1}=X_{a2}+w_2.....X_{an}=X_j+w_{n+1})的月份对,只需分别计算其最大可能差与最小可能差,这和用弗洛伊德最短路松弛更新有同曲同工之妙,不过这个新看法我觉得很好。

代码

#include <iostream>
#include <cstring>

const int MAXN = 105;

int T, n, m;
int longDis[MAXN][MAXN], shortDis[MAXN][MAXN], access[MAXN][MAXN];//access[i][j]表示两个点i,j是否可达

int main(){
	std::ios::sync_with_stdio(false);
	std::cin.tie(0);
	std::cout.tie(0);

	std::cin >> T;

	while(T--){
		for(int i = 0; i < MAXN; ++i){
			for(int j = 0; j < MAXN; ++j){
				longDis[i][j]=-1e9-7, shortDis[i][j]=1e9+7;
				access[i][j]=0;
			}
		}

		std::cin >> n >> m;

		for(int i = 1; i <= m; ++i){
			int s, t, v;
			std::cin >> s >> t >> v;
			longDis[s-1][t] = v, shortDis[s-1][t] = v;
			access[s-1][t] = 1;
		}

		for(int i = 0; i <= n; ++i){
			for(int j = 0; j <= n; ++j){
				for(int k = 0; k <= n; ++k){
					access[j][k]|=access[j][i]&access[i][k];
				}
			}
		}

		for(int i = 0; i <= n; ++i){
			for(int j = 0; j <= n; ++j){
				for(int k = 0; k <= n; ++k){
					if((! access[j][k]) || (! access[j][i]) || (! access[i][k]) || j >= k || j >= i || i >= k){
						continue;
					}

					longDis[j][k] = std::max(longDis[j][k], longDis[j][i] + longDis[i][k]);
					shortDis[j][k] = std::min(shortDis[j][k], shortDis[j][i] + shortDis[i][k]);
				}
			}
		}

		bool p=0;
		for(int i = 0; i <= n; ++i){
			for(int j = 0; j <= n; ++j){
				if((! access[i][j]) || i >= j){
					continue;
				}

				if(longDis[i][j] != shortDis[i][j]) {
					p=1;
				}
			}
		}

		if(p){
			std::cout << "false" << "\n";
		} else{
			std::cout << "true" << "\n";
		}
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值