题目描述

输入输出格式

输入格式:

从文件\(input.txt\)中读入数据,文件第一行为一个正整数\(w\),其中\(w < 100\),表示有\(w\)组数据,即\(w\)个账本,需要你判断。每组数据的第一行为两个正整数\(n\)\(m\),其中\(n < 100,m < 1000\),分别表示对应的账本记录了多少个月的收入情况以及偷看了多少次账本。接下来的\(m\)行表示刁姹偷看\(m\)次账本后记住的\(m\)条信息,每条信息占一行,有三个整数\(s\)\(t\)\(v\),表示从第\(s\)个月到第\(t\)个月(包含第\(t\)个月)的总收入为\(v\),这里假设\(s\)总是小于等于\(t\)

输出格式:

输出文件\(output.txt\)中包含\(w\)行,每行是\(true\)\(false\),其中第\(i\)行为\(true\)当且仅当第\(i\)组数据,即第\(i\)个账本不是假的;第\(i\)行为\(false\)当且仅当第i组数据,即第\(i\)个账本是假的。

输入输出样例

输入样例#1:

2
3 3
1 2 10
1 3 -5
3 3 -15
5 3
1 5 100
3 5 50
1 2 51

输出样例#1:

true
false

思路:题目中的条件可以转化为\(v \leq d[t]-d[s] \leq v\),这就是这个题目中唯一的约束条件,然后对于每组询问建边,跑\(spfa\)即可,如果说在第i组询问中存在负环,说明第\(i\)本账本是假的,输出\(false\),否则输出\(true\)

代码:

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<queue>
#define maxn 100007
using namespace std;
int num,t,n,m,head[maxn],dis[maxn],vis[maxn],in[maxn];
inline int qread() {
  char c=getchar();int num=0,f=1;
  for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
  for(;isdigit(c);c=getchar()) num=num*10+c-'0';
  return num*f;
}
struct node {
  int v,w,nxt;
}e[200007];
inline void ct(int u, int v, int w) {
  e[++num].v=v;
  e[num].w=w;
  e[num].nxt=head[u];
  head[u]=num;
}
inline bool spfa() {
  memset(dis,0x3f,sizeof(dis));
  memset(vis,0,sizeof(vis));
  memset(in,0,sizeof(in));
  queue<int>q;
  q.push(0),vis[0]=1,in[0]=1,dis[0]=0;
  while(!q.empty()) {
    int u=q.front();
    q.pop(),vis[u]=0;
    for(int i=head[u];i;i=e[i].nxt) {
      int v=e[i].v;
      if(dis[v]>dis[u]+e[i].w) {
        dis[v]=dis[u]+e[i].w;
        if(!vis[v]) {
          vis[v]=1;
          in[v]++;
          if(in[v]>n) return 1;
          q.push(v);
        }
      }
    }
  }
  return 0;
}
int main() {
  t=qread();
  while(t--) {
    n=qread(),m=qread();
    memset(head,0,sizeof(head));
    num=0;
    for(int i=1,u,v,w;i<=m;++i) {
      u=qread(),v=qread(),w=qread();
      ct(u-1,v,w),ct(v,u-1,-w);
    }
    if(spfa()) printf("false\n");
    else printf("true\n");
  }
  return 0;
}