• luogu 2474 [SCOI2008]天平


    输入输出样例

    输入 #1
    6 2 5
    ?+????
    -?+???
    ?-????
    ????+?
    ???-?+
    ????-?
    输出 #1
    1 4 1
    输入 #2
    14 8 4
    ?+???++?????++
    -??=?=???????=
    ??????????=???
    ?=??+?==??????
    ???-???-???-??
    -=????????????
    -??=???=?-+???
    ???=+?=???????
    ??????????????
    ??????+???????
    ??=???-????-??
    ????+?????+???
    -?????????????
    -=????????????
    输出 #2
    18 12 11

    说明/提示

    4<=n<=50

    分析

    Part 1 建图

    这道题,点与点之间大小相对,变量之间有约束条件

    还是差分约束最好了

    怎么建图,他只给了大小关系,并没有说具体数值,难道直接连一条长度为1 或-1的边?

    再看题目所求:

    你把其中两个砝码A 和B 放在天平的左边,需要另外选出两个砝码放在天平的右边。问:有多少种选法使得天平的左边重(c1)、一样重(c2)、右边重(c3)?(只有结果保证惟一的选法才统计在内)

    明显求的是一个大小关系

    我们在读题,题目上说“存在一种情况符合该矩阵”,所以可能不止一种

    这样,我们便不能直接将距离赋值为1了,而是需要保留这个范围

    留意到数据范围,结合可以“选任意两个砝码”,用矩阵存图会比较方便

    既然我们要求的是一个范围,连边的时候,连上下界即可

    用一个数组存最大的差,一个数组存最小的差

    Part 2 求解 

    想要求得这个差分约束系统的解,我们的目的是求出各个砝码的取值范围

    由于砝码自由组合,还是用Floyd比较好

    这样求出来的是什么?是两个砝码之间的差的取值范围

    要用这个推出各个砝码重量的取值范围吗?

    不必,也不行

    就算推出来了,有些砝码的有些取值是不能同时取到的

    我们看题,所求的是:

    i+j<a+b的个数(i-a<b-j)(j-a<b-i)

    i+j>a+b的个数(i-a>b-j)(j-a>b-i)

    i+j=a+b的个数(i-a=b-j)(i-b=a-j)

    这样,就可以将和转化为差求解了

    再看题:

    只有结果保证惟一的选法才统计在内

    这是一个恒成立问题,所以要最大的可能小于最小的可能才叫恒成立

    等于的时候,还需要最大值等于最小值

     

    完结撒花!

    代码

      1 /************************
      2 User:Mandy.H.Y
      3 Language:c++
      4 Problem:luogu2474
      5 Algorithm:
      6 ************************/
      7 
      8 #include<bits/stdc++.h>
      9 
     10 using namespace std;
     11 
     12 const int maxn = 55;
     13 
     14 int n,a,b; 
     15 char c[maxn][maxn]; 
     16 int dis[maxn][maxn],dis1[maxn][maxn];
     17 
     18 template<class T>inline void read(T&x){
     19     x = 0;bool flag = 0;char ch = getchar();
     20     while(!isdigit(ch)) flag |= ch == '-',ch = getchar();
     21     while(isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48),ch = getchar();
     22     if(flag) x = -x;
     23 }
     24 
     25 template<class T>void putch(const T x){
     26     if(x > 9) putch(x / 10);
     27     putchar(x % 10 | 48);
     28 }
     29 
     30 template<class T>void put(const T x){
     31     if(x < 0) putchar('-'),putch(-x);
     32     else putch(x);
     33 }
     34 
     35 void file(){
     36     freopen("2474.in","r",stdin);
     37 //    freopen("2474.out","w",stdout);
     38 }
     39 
     40 void readdata(){
     41     read(n);read(a);read(b);
     42     for(int i = 0;i < n; ++ i) scanf("%s",c[i]);
     43     for(int i = 0;i < n; ++ i) c[i][i] = '=';
     44 }
     45 
     46 void work(){ 
     47 
     48 
     49     for(int i = 1;i <= n; ++ i){ 
     50         for(int j = 1;j <= n; ++ j){
     51             switch(c[i-1][j-1]){
     52                 case '-':{
     53                     dis[i][j] = 1; dis1[i][j] = 2;
     54                     dis[j][i] = -2; dis1[j][i] = -1;
     55                     break;//    dis是最小值,dis1最大值 
     56                 }//虽然样例是对称的,但题目上没说,还是连双向 
     57                     dis[j][i] = 1;dis1[j][i] = 2;
     58                     dis[i][j] = -2;dis1[i][j] = -1;
     59                     break;
     60                 }
     61                 case '=':{
     62                     dis[i][j] = 0;dis[j][i] = 0;
     63                     dis1[j][i] = 0;dis1[i][j] = 0;
     64                     break;
     65                 }
     66                 default:{
     67                     dis[i][j] = -2;dis1[i][j] = 2;
     68                     dis[j][i] = -2;dis1[j][i] = 2;
     69                     break;
     70                 }//?的,赋为最大/小的值 ,可以更新 
     71             }
     72         }
     73     }
     74 //    以最大的可能距离求最短路,便是他们之间的最大差
     75 //    因为最大差就是“最多,大了多少”,它的限制便是最少的“最多” 
     76     for(int k = 1;k <= n; ++ k)
     77         for(int i = 1;i <= n; ++ i)
     78             for(int j = 1;j <= n; ++ j){
     79                 if(i == j || i == k || j == k) continue;
     80                 //初值的关系,最好判断一下 
     81                 dis[i][j] = max(dis[i][j],dis[i][k] + dis[k][j]);
     82                 dis1[i][j] = min(dis1[i][j],dis1[i][k] + dis1[k][j]);
     83             }
     84     int c1 = 0,c2 = 0,c3 = 0;
     85     for(int i = 1;i <= n; ++ i){
     86         if(i == a || i == b) continue;
     87         for(int j = 1+i;j <= n; ++ j){
     88             if(j == a || j == b) continue;
     89             c1 += (dis[i][a] > dis1[b][j] || dis[i][b] > dis1[a][j]);
     90             
     91             c3 += (dis[a][i] > dis1[j][b] || dis[b][i] > dis1[j][a]);
     92             
     93             c2 += ((dis[i][a] == dis1[b][j] && dis[i][a] == dis1[i][a] && dis[b][j] == dis1[b][j]) || 
     94                    (dis[i][b] == dis1[a][j] && dis[i][b] == dis1[i][b] && dis[a][j] == dis1[a][j]));
     95         }
     96     }        
     97             
     98     put(c1);putchar(' ');
     99     put(c2);putchar(' ');
    100     put(c3);
    101 }
    102 
    103 int main(){
    104 //    file();
    105     readdata();
    106     work();
    107     return 0;
    108 }
    View Code
  • 相关阅读:
    带你一分钟理解闭包js面向对象编程
    ThinkPad X1 Carbon 2022领衔,联想ThinkFamily 2022一众新品发布
    C#中const用法 C#中const用法详解
    ThinkPad哪个产品系列比较好?
    VB/VBA,可能超乎你的想象
    世界六大顶尖的软件强国
    2021年李宁跑鞋矩阵分析及挑选购买攻略
    .NET Core与.NET Framework、Mono之间的关系
    李宁动真格!多款「弹簧鞋」同时发售!扔地下能弹回来那种
    ts 泛型
  • 原文地址:https://www.cnblogs.com/Mandy-H-Y/p/11488491.html
Copyright © 2020-2023  润新知