BZOJ[HNOI2005]狡猾的商人(差分约束)
1202: [HNOI2005]狡猾的商人
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 4969 Solved: 2496
[Submit][Status][Discuss]
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
false
HINT
Source
题解:对于给的i,j,w,我们可以假设sum[i]为前i天的和;则sum[j]-sum[i-1]==w; ==>sum[j]-sum[i-1]<=w&&sum[i-1]-sum[j]<=-w;
如果能够找到从起点到其他点的最短距离,则为真;如果有环的话说明存在矛盾的地方使其距离可以一直减小;
注意:并不是任意两点都可以到达,故分几个图寻找;
参考代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define clr(a,val) memset(a,val,sizeof a) 4 #define lowbit(x) x&-x 5 #define PI acos(-1.0) 6 typedef long long ll; 7 const int INF=0x3f3f3f3f; 8 int read() 9 { 10 int x=0,f=1;char ch=getchar(); 11 while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();} 12 while(ch>='0'&&ch<='9') {x=x*10+ch-'0'; ch=getchar();} 13 return x*f; 14 } 15 const int maxn=1010; 16 int T,n,m,x,y,z,tot,cnt[maxn]; 17 int head[maxn],dis[maxn],vis[maxn]; 18 struct Edge{ 19 int v,w,nxt; 20 } edge[maxn<<1]; 21 22 void Init() 23 { 24 tot=0; clr(head,-1); 25 clr(cnt,0); 26 } 27 28 void addedge(int u,int v,int w) 29 { 30 edge[tot].v=v; 31 edge[tot].w=w; 32 edge[tot].nxt=head[u]; 33 head[u]=tot++; 34 } 35 36 bool SPFA(int s) 37 { 38 queue<int> q; 39 clr(dis,INF);clr(vis,0); 40 dis[s]=0; vis[s]=1; 41 q.push(s); 42 while(!q.empty()) 43 { 44 int u=q.front(); q.pop(); vis[u]=0; 45 for(int i=head[u];~i;i=edge[i].nxt) 46 { 47 int v=edge[i].v; 48 if(dis[v]>dis[u]+edge[i].w) 49 { 50 dis[v]=dis[u]+edge[i].w; 51 if(!vis[v]) 52 { 53 q.push(v);vis[v]=1; 54 if(++cnt[v]>n) return false; 55 } 56 } 57 } 58 } 59 return true; 60 } 61 62 int main() 63 { 64 T=read(); 65 while(T--) 66 { 67 Init(); 68 n=read();m=read(); 69 for(int i=1;i<=m;++i) 70 { 71 x=read();y=read();z=read(); 72 addedge(x-1,y,z);addedge(y,x-1,-z); 73 } 74 bool flag=true; 75 for(int i=0;i<=n;++i) 76 { 77 if(cnt[i]) continue; 78 if(!SPFA(i)) {flag=false; break;} 79 } 80 if(flag) puts("true"); 81 else puts("false"); 82 } 83 return 0; 84 }