题目描述
刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的。账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), 。当 Ai大于0时表示这个月盈利Ai 元,当 Ai小于0时表示这个月亏损Ai 元。所谓一段时间内的总收入,就是这段时间内每个月的收入额的总和。 刁姹的任务是秘密进行的,为了调查商人的账本,她只好跑到商人那里打工。她趁商人不在时去偷看账本,可是她无法将账本偷出来,每次偷看账本时她都只能看某段时间内账本上记录的收入情况,并且她只能记住这段时间内的总收入。 现在,刁姹总共偷看了m次账本,当然也就记住了m段时间内的总收入,你的任务是根据记住的这些信息来判断账本是不是假的。
链接
题解
算法1 (差分约束系统)
思路
l
,r
,s
,表示从l
到r
的和是s
- 维护前缀和 \(sum_i=\sum\limits_{j=1}^{i}A_j\)
- 于是可以将
l-1
和r
连一条-s
的边,r
和l-1
连一条s
的边,即保证 \(sum_r-sum_{l-1}=s\) - 最后跑 spfa 判断是否有负环
代码
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define MAXN 105
using namespace std;
typedef pair <int,int> pii;
typedef long long ll;
int T,n,m,Q[MAXN],cnt[MAXN];
ll dis[MAXN];
bool vis[MAXN],flg;
vector <pii> e[MAXN];
void spfa(int s){
int H=0,T=1;
Q[1]=s,vis[s]=1,dis[s]=0;
while (H!=T){
int x=Q[++H%=MAXN]; vis[x]=0; cnt[x]++;
if (cnt[x]>n){
flg=1;
return;
}
for (int i=0;i<e[x].size();i++){
int v=e[x][i].first;
if (dis[x]+e[x][i].second<dis[v]){
dis[v]=dis[x]+e[x][i].second;
if (!vis[v]){
vis[v]=1;
Q[++T%=MAXN]=v;
}
}
}
}
}
int main(){
freopen("trader.in","r",stdin);
freopen("trader.out","w",stdout);
scanf("%d",&T);
while (T--){
memset(dis,63,sizeof(dis));
memset(vis,0,sizeof(vis));
memset(cnt,0,sizeof(cnt));
memset(Q,0,sizeof(Q));
flg=0;
scanf("%d%d",&n,&m);
for (int i=0;i<=n;i++) e[i].clear();
for (int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
e[u-1].push_back(make_pair(v,-w));
e[v].push_back(make_pair(u-1,w));
}
for (int i=1;i<=n;i++){
if (!cnt[i]) spfa(i);
if (flg) break;
}
if (flg)
puts("false");
else
puts("true");
}
return 0;
}