题目传送门
https://www.luogu.com.cn/problem/P2294
题目分析
看到这种多元未知数要求一定关系的题目,通常会使用差分约束算法查看是否有解,但注意到本题仅要求相等,这使得我们可以用更简单的方法来判断。设 是前
个月的收入总和,输入告诉我们了
个形如
的信息,其中
,
分别代表记账区间
中的
与区间内的总收益,由于真实的账本某个月的收入是一定的,因此如果该账本是真实的,其中输入的信息一定保持一致,即不论通过何种方法运算两个特定月份所赚的钱数,答案总是一致的。设
,
分别代表两个月之间按题目信息算出的最大收益与最小收益,如果对于所有可以计算(可以计算只的是
且存在足够多的关系使得
)的月份对,只需分别计算其最大可能差与最小可能差,这和用弗洛伊德最短路松弛更新有同曲同工之妙,不过这个新看法我觉得很好。
代码
#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;
}
356

被折叠的 条评论
为什么被折叠?



