[HNOI2005]狡猾的商人

题意:
有一个数列,告诉你m组区间和,问区间和中是否有冲突(即错误)
比如2 4 3 4 7 5 (你不知道这个数列,但都是正整数)
告诉你:
2 ~ 4 = 11
1 ~ 3 = 9
1 ~ 2 = 11
这就不合法,虽然数列未知,但1~2的区间和比1~3的还小,这显然是不可能的

题解:
首先它告诉我们的是区间和,那首先就要想到前缀和。
于是我们设dis[i]表示1~i的区间和,
那么题目实际上就是告诉你这样一组等式:
dis[i] - dis[j] = k[t]
dis[k] - dis[l] = k[t+1]
.......
是不是很眼熟?
没错就是差分约束
但由于这里是等号,而不是大于小于,
因此我们的目标不再是找最短路
因为最短路是在尽量不等式
而这里是等式
所以我们的目标应该是判断到达一个点的所有路径是否相等
一开始我想的是跑两遍spfa,一遍找最短路,一遍找最长路,
再判断最短路和最长路是否相等,
后来A完之后看大佬的,才发现其实直接在找最短路的时候,
每次访问到一个点就判断是否与之前找到的路径长度相同就可以了
如果有至少一个不同,那就是不合法

 

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define R register int
  4 #define inf -2139062144
  5 #define AC 150
  6 #define ACway 5000
  7 int T,n,m;
  8 int Head[AC],date[ACway],Next[ACway],length[ACway],tot;
  9 int q[ACway],head,tail;
 10 int min_dis[AC],max_dis[AC];
 11 bool vis[AC];
 12 /*猜一个结论,
 13 对于dis[i] - dis[j] = w[k],
 14 连 j ---> i : w[k]的边,
 15 如果合法,那么原本的dis[i]将无法被更新????
 16 也就是说,通过0号节点走任意路径到达的任意节点的权值和是一定的,
 17 简单来说就是最短路 == 最长路
 18 or 满足两个差分约数条件?
 19 即dis[i] - dis[j] <= w[k] 
 20 + dis[j] - dis[i] <= w[k](dis[i] - dis[j] >= w[k])
 21 算了还是最短路 == 最长路吧,,,不然不知道怎么判断*/
 22 inline int read()
 23 {
 24     int x=0;char c=getchar();bool z=false;
 25     while(c > '9' || c < '0') {if(c == '-') z=true; c=getchar();}
 26     while(c >= '0' && c <= '9') x=x * 10 + c - '0' , c=getchar();
 27     if(!z) return x;
 28     else return -x;
 29 }
 30 
 31 inline void add(int f,int w,int S)
 32 {
 33     //printf("%d ---> %d : %d\n",f,w,S);
 34     date[++tot]=w,Next[tot]=Head[f],length[tot]=S,Head[f]=tot;
 35 }
 36 
 37 void pre()
 38 {
 39     int a,b,c;
 40     n=read(),m=read();
 41     tot=0;
 42     memset(Head,-1,sizeof(Head));//因为有0号几点的参与,所以是置为-1,而不是0    
 43     for(R i=1;i<=m;i++)
 44     {
 45         a=read(),b=read(),c=read();//因为是sum[b] - sum[a-1] 
 46         add(a-1,b,c);//类似前缀和的东西
 47     }
 48     memset(max_dis,128,sizeof(max_dis));
 49     memset(min_dis,127,sizeof(min_dis));
 50 }
 51 
 52 #define dis min_dis
 53 void spfa(int b)//search for the shortest road
 54 {
 55     int x,now;
 56     memset(dis,127,sizeof(dis));
 57     head=tail=0;//先把0放入
 58     q[++tail]=b , dis[b]=0;//因为直接把tail赋为1的话,q[1]可能不为0
 59     memset(vis,0,sizeof(vis));
 60     while(head < tail)
 61     {
 62         x=q[++head];
 63         for(R i=Head[x]; i!=-1 ;i=Next[i])
 64         {
 65             now=date[i];
 66             if(dis[now] > dis[x] + length[i])
 67             {
 68                 dis[now] = dis[x] + length[i];
 69                 if(!vis[now]) q[++tail]=now,vis[now]=true;
 70             }
 71         }
 72         vis[x]=false;
 73     }
 74 }
 75 #undef dis //仿佛发现神器。。。。
 76 
 77 #define dis max_dis
 78 void SPFA(int b)//search for the longest road
 79 {
 80     int x,now;
 81     memset(dis,128,sizeof(dis));
 82     head=tail=0;
 83     q[++tail]=b , dis[b]=0;
 84     memset(vis,0,sizeof(vis));
 85     while(head < tail)
 86     {
 87         x=q[++head];
 88         for(R i=Head[x]; i!=-1 ;i=Next[i])
 89         {
 90             now=date[i];
 91             if(dis[now] < dis[x] + length[i])
 92             {
 93                 dis[now] = dis[x] + length[i];
 94                 if(!vis[now]) q[++tail]=now,vis[now]=true;
 95             }
 96         }
 97         vis[x]=false;
 98     }    
 99 }
100 #undef dis
101 
102 void solve()
103 {
104     bool flag;
105     scanf("%d",&T);
106     for(R i=1;i<=T;i++)
107     {
108         pre();//要遍历完每一个联通块,不然就会有些部分访问不到
109         flag=false;
110         for(R j=0;j<=n;j++)
111         {
112             if(max_dis[j] == inf) 
113             {
114                 spfa(j);
115                 SPFA(j);
116             }
117             for(R k=1;k<=n;k++) 
118             {    
119                 if(max_dis[k] == inf) continue;
120                 if(max_dis[k] != min_dis[k])
121                 {
122                     flag=true;
123                     printf("false\n");
124                     break;
125                 }
126             }
127             if(flag) break;
128         }
129         if(!flag) printf("true\n");
130     }
131 }
132 
133 int main()
134 {
135 //    freopen("in.in","r",stdin);
136     solve();
137 //    fclose(stdin);
138     return 0;
139 }

 

posted @ 2018-06-02 14:10  ww3113306  阅读(413)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。