[HNOI2005]狡猾的商人

题目描述

输入输出格式

输入格式 

从文件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

题解:

1.差分约束,直接x-y连v的边,并且y-x连-v的边,然后spfa找负环

2.带权并查集,每一次合并find(y)和x并修改路径上的dis值,顺便路径压缩.然后如果在同一集合中直接判断矛盾即可

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cstdio>
 6 #include <cmath>
 7 using namespace std;
 8 const int N=505;
 9 int fa[N],dis[N];
10 int find(int x){
11     if(x==fa[x])return x;
12     int t=find(fa[x]);
13     if(fa[x]!=fa[fa[x]])
14     dis[x]+=dis[fa[x]];
15     fa[x]=t;
16     return fa[x];
17 }
18 void work(){
19     int n,m,x,y,z,flag=0;
20     scanf("%d%d",&n,&m);
21     for(int i=1;i<=n+1;i++)fa[i]=i,dis[i]=0;
22     for(int i=1;i<=m;i++){
23         scanf("%d%d%d",&x,&y,&z);
24         y++;
25         if(find(x)==find(y)){
26             if(dis[y]-dis[x]!=z && !flag){
27                 printf("false
");
28                 flag=1;
29             }
30         }
31         else
32             dis[find(y)]=z-dis[y],fa[find(y)]=x,find(y);
33     }
34     if(!flag)
35     printf("true
");
36 }
37 int main()
38 {
39     freopen("sum.in","r",stdin);
40     freopen("sum.out","w",stdout);
41     int T;
42     scanf("%d",&T);
43     while(T--){
44         work();
45     }
46     return 0;
47 }
带权并查集
 1 #include <algorithm>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <cmath>
 6 using namespace std;
 7 const int N=505,M=5005;
 8 int n,m,num=0,head[N];
 9 struct Lin{
10     int next,to,dis;
11 }a[M<<1];
12 void init(int x,int y,int z){
13     a[++num].next=head[x];a[num].to=y;a[num].dis=z;head[x]=num;
14 }
15 int q[N*10],f[N];bool vis[N];
16 bool check(int s){
17     int t=0,sum=1,x,u;q[1]=s;vis[s]=true;
18     while(t!=sum){
19         t++;x=q[t];
20         for(int i=head[x];i;i=a[i].next){
21             u=a[i].to;
22             if(!vis[u]){
23                 vis[u]=true;
24                 f[u]=f[x]+a[i].dis;
25                 q[++sum]=u;
26             }
27             else if(f[x]+a[i].dis!=f[u])return false;
28         }
29     }
30     return true;
31 }
32 void Clear(){
33     memset(f,0,sizeof(f));
34     memset(vis,0,sizeof(vis));
35     memset(head,0,sizeof(head));
36     num=0;
37 }
38 void work(){
39     Clear();
40     int x,y,z;
41     scanf("%d%d",&n,&m);
42     for(int i=1;i<=m;i++){
43         scanf("%d%d%d",&x,&y,&z);
44         init(x,y+1,z);init(y+1,x,-z);
45     }
46     bool fg=false;
47     for(int i=1;i<=n;i++){
48         if(vis[i])continue;
49         if(!check(i)){
50             fg=true;
51             break;
52         }
53     }
54     if(!fg)printf("true
");
55     else printf("false
");
56 }
57 int main()
58 {
59     freopen("sum.in","r",stdin);
60     freopen("sum.out","w",stdout);
61     int T;
62     scanf("%d",&T);
63     while(T--)
64         work();
65     return 0;
66 }
spfa乱搞
原文地址:https://www.cnblogs.com/Yuzao/p/7206783.html