zoukankan      html  css  js  c++  java
  • [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
    ",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
    ");
    124                     break;
    125                 }
    126             }
    127             if(flag) break;
    128         }
    129         if(!flag) printf("true
    ");
    130     }
    131 }
    132 
    133 int main()
    134 {
    135 //    freopen("in.in","r",stdin);
    136     solve();
    137 //    fclose(stdin);
    138     return 0;
    139 }
  • 相关阅读:
    寒假第七天
    寒假第六天
    寒假第五天
    寒假第四天
    leetcode 105 从前序与中序遍历序列构造二叉树
    leetcode 268 丢失的数字
    leetcode 141 环形链表
    判断顶点是否在三角形内部
    java 基本数据类型
    leetcode 20 有效的括号
  • 原文地址:https://www.cnblogs.com/ww3113306/p/9125284.html
Copyright © 2011-2022 走看看