luogu 2294 [HNOI2005]狡猾的商人

Description

刁姹接到一个任务,为税务部门调查一位商人的账本,看看账本是不是伪造的。账本上记录了n个月以来的收入情况,其中第i 个月的收入额为Ai(i=1,2,3...n-1,n), 。当 Ai大于0时表示这个月盈利Ai 元,当 Ai小于0时表示这个月亏损Ai 元。所谓一段时间内的总收入,就是这段时间内每个月的收入额的总和。 刁姹的任务是秘密进行的,为了调查商人的账本,她只好跑到商人那里打工。她趁商人不在时去偷看账本,可是她无法将账本偷出来,每次偷看账本时她都只能看某段时间内账本上记录的收入情况,并且她只能记住这段时间内的总收入。 现在,刁姹总共偷看了m次账本,当然也就记住了m段时间内的总收入,你的任务是根据记住的这些信息来判断账本是不是假的。

Input

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

Output

包含w行,每行是true或false,其中第i行为true当且仅当第i组数据,即第i个账本不是假的;第i行为false当且仅当第i组数据,即第i个账本是假的。

Sample Input


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

Sample Output

true 
false
 

分析

解法一 差分约束

s月到t月共收入v元,从s-1到t连一条长度为v的边

图没有环

对于每一个入度为零的点,跑两遍SPFA(最长/最短)

比较各个点的(能到达的点)两个距离是否一样,不一样就false,

一样就继续找入度为零的点

注意每一次SPFA前要初始化

因为这个距离是相对起点而言,所以各个起点是独立的

不能只在最后判断最长最短是否一样

  1 /*********************
  2 User:Mandy.H.Y
  3 Language:c++
  4 Problem:luogu2294
  5 Algorithm:
  6 *********************/
  7 #include<bits/stdc++.h>
  8 
  9 using namespace std;
 10 
 11 const int maxn = 105;
 12 const int maxm = 1005;
 13 const int mod = 1e5;
 14 
 15 int W,n,m,size;
 16 int first[maxn];
 17 int dis1[maxn],dis2[maxn],ind[maxn];
 18 int q[100005],l,r;
 19 bool vis[maxn];
 20 
 21 struct Edge{
 22     int v,nt,w;
 23 }edge[maxm];
 24 
 25 template<class T>inline void read(T &x){
 26     x = 0;bool flag = 0;char ch = getchar();
 27     while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
 28     while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
 29     if(flag) x = -x;
 30 }
 31 
 32 void file(){
 33     freopen("2294.in","r",stdin);
 34     freopen("2294.out","w",stdout);
 35 }
 36 
 37 void init(){
 38     size = 0;
 39     memset(first,0,sizeof(first));
 40     memset(edge,0,sizeof(edge));
 41     memset(ind,0,sizeof(ind));
 42 }
 43 
 44 void eadd(int u,int v,int w){
 45     edge[++size].v = v;
 46     edge[size].w = w;
 47     edge[size].nt = first[u];
 48     first[u] = size;
 49 }
 50 
 51 void readdata(){
 52     read(n);read(m);
 53     for(int i = 1;i <= m; ++ i){
 54         int u,v,w;
 55         read(u);read(v);read(w);
 56         eadd(u-1,v,w);
 57         ind[v] ++;
 58     }
 59 }
 60 
 61 bool SPFA(int x){
 62     l = r = 0;
 63     q[r++] = x;
 64     memset(vis,0,sizeof(vis));
 65     while(l != r){
 66         int u = q[l];
 67         l ++ ; l %= mod;
 68         int rr = (r - 1 + mod) % mod;
 69         if(l != r) if(dis1[q[l]] > dis1[q[rr]]) swap(q[l],q[rr]);
 70         vis[u] = 0;
 71         for(int i = first[u];i;i = edge[i].nt){
 72             int v = edge[i].v;
 73             int w = edge[i].w;
 74             if(dis1[v] > dis1[u] + w){
 75                 dis1[v] = dis1[u] + w;
 76                 if(!vis[v]){
 77                     q[r++] = v;
 78                     vis[v] = 1;
 79                     r %= mod;
 80                     int rr = (r - 1 + mod) % mod;
 81                     if(l != r) if(dis1[q[l]] > dis1[q[rr]]) swap(q[l],q[rr]);
 82                 } 
 83             }
 84         }
 85     }
 86     
 87         
 88     l = r = 0;
 89     q[r++] = x;
 90     memset(vis,0,sizeof(vis));
 91     while(l != r){
 92         int u = q[l];
 93         l ++ ; l %= mod;
 94         int rr = (r - 1 + mod) % mod;
 95         if(l != r) if(dis2[q[l]] < dis2[q[rr]]) swap(q[l],q[rr]);
 96         vis[u] = 0;
 97         for(int i = first[u];i;i = edge[i].nt){
 98             int v = edge[i].v;
 99             int w = edge[i].w;
100             if(dis2[v] < dis2[u] + w){
101                 dis2[v] = dis2[u] + w;
102                 if(!vis[v]){
103                     q[r++] = v;
104                     vis[v] = 1;
105                     r %= mod;
106                     int rr = (r - 1 + mod) % mod;
107                     if(l != r) if(dis2[q[l]] < dis2[q[rr]]) swap(q[l],q[rr]);
108                 }
109             }
110         }
111     }
112     
113     for(int i = 1;i <= n; ++ i){
114         if(dis1[i] != 0x3f3f3f3f && dis1[i] != dis2[i]){
115             return 0;
116         }
117     }
118     return 1;
119     
120 }
121 
122 void work(){
123     init();
124     readdata();
125     
126     for(int i = 0;i <= n; ++ i){
127         if(ind[i] == 0){
128             
129             memset(dis1,0x3f3f3f3f,sizeof(dis1));
130             memset(dis2,128,sizeof(dis2));
131 
132             dis1[i] = 0;
133             dis2[i] = 0;
134             if(!SPFA(i)) {
135                 puts("false");
136                 return;
137             }
138         }
139     }
140     puts("true");
141 }
142 
143 int main(){
144 //    file();
145     read(W);
146     while(W -- ) work();
147     return 0;
148 }
View Code

解法二 带权并查集

原文地址:https://www.cnblogs.com/Mandy-H-Y/p/11468127.html