[HNOI2005]狡猾的商人
Posted Z-Y-Y-S
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[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
题解
差分约束,对于x1-x2=k,那么要同时满足x1-x2>=k和x1-x2<=k,即双向都建边,只是权值一正一负
当一个节点不同路径到达一个节点的距离不同时即为false,否则为true
我的方法不需要判负环,因为在bfs中不同路径不同距离就会弹出,已经包含了负环的情况
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 struct Node 7 { 8 int next,to,dis; 9 }edge[100001]; 10 int num,head[2001],q[1000001],vis[2001],dist[2001],ss,n,m; 11 void add(int u,int v,int d) 12 { 13 num++; 14 edge[num].next=head[u]; 15 head[u]=num; 16 edge[num].to=v; 17 edge[num].dis=d; 18 } 19 bool bfs(int x) 20 {int h,t,i; 21 h=0;t=1; 22 q[1]=x; 23 vis[x]=1; 24 while (h<t) 25 { 26 h++; 27 h%=1000000; 28 int u=q[h]; 29 for (i=head[u];i;i=edge[i].next) 30 { 31 int v=edge[i].to; 32 if (dist[v]==ss) 33 { 34 dist[v]=dist[u]+edge[i].dis; 35 if (vis[i]==0) 36 { 37 t++; 38 t%=1000000; 39 q[t]=v; 40 vis[i]=1; 41 } 42 } 43 else if (dist[v]!=dist[u]+edge[i].dis) 44 return 1; 45 } 46 } 47 return 0; 48 } 49 int main() 50 {int T,i,x,y,d,sign; 51 cin>>T; 52 while (T--) 53 { 54 cin>>n>>m; 55 num=0; 56 memset(edge,0,sizeof(edge)); 57 memset(head,0,sizeof(head)); 58 for (i=1;i<=m;i++) 59 { 60 scanf("%d%d%d",&x,&y,&d); 61 add(x,y+1,d); 62 add(y+1,x,-d); 63 } 64 sign=0; 65 memset(dist,127,sizeof(dist)); 66 memset(vis,0,sizeof(vis)); 67 ss=dist[0]; 68 for (i=1;i<=n;i++) 69 if (vis[i]==0&&bfs(i)) 70 { 71 sign=1; 72 break; 73 } 74 if (sign==1) 75 printf("false\n"); 76 else printf("true\n"); 77 } 78 }
以上是关于[HNOI2005]狡猾的商人的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ-1202: [HNOI2005]狡猾的商人 (并查集+前缀和)
bzoj 1202: [HNOI2005]狡猾的商人 并查集好题