ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

luogu 2474 [SCOI2008]天平

2019-09-09 09:53:24  阅读:261  来源: 互联网

标签:dis1 2474 int luogu ch SCOI2008 maxn 砝码 dis


输入输出样例

输入 #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

 

标签:dis1,2474,int,luogu,ch,SCOI2008,maxn,砝码,dis
来源: https://www.cnblogs.com/Mandy-H-Y/p/11488491.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有