题解:
差分约束学得实在是太烂了,,,,QAQ
这里先记下:
a - b >= x ---> a >= b + x ----> b ---> a = x(b连a,边权为x), ----> 找最长路, --->f[a][b]对应a - b的最小值,
a - b <=x ---->后面的都反过来就好了
关于这道题:
首先我们可以发现它实际上就是告诉了我们一堆这样的关系:
a > b,
a < b,
a = b,
所以我们应该要想到差分约束,
如果直接连,我们发现连边权都没有,,,,
因此我们要对式子进行转化,
以a > b为例:
a > b ----> a - b > 0 ---> a - b >= 1 ---> a >= b + 1,
这就变成了形如上面的式子,
但是我们发现我们得到了a - b 的最大值和最小值还不够,
于是我们对目标进行转化,
题目要求a + b ? x + y,其中a + b给定,
那么小于的情况实际上就是a - x < y - b || a - y < x - b,
如果是大于,那直接换符号即可,
如果是等于还要判断a - x的最大最小值相等,因为要确定的结果才能被计入答案,
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 52 5 /*考虑差分约束中路的长度的意义。 6 n很小,所以考虑floyd*/ 7 int n,a,b,ans1,ans2,ans3; 8 int f_min[AC][AC], f_max[AC][AC]; 9 char c[AC]; 10 11 inline void upmin(int &a,int b) 12 { 13 if(b < a) a = b; 14 } 15 16 inline void upmax(int &a,int b) 17 { 18 if(b > a) a = b; 19 } 20 21 inline void pre() 22 { 23 scanf("%d%d%d",&n,&a,&b); 24 memset(f_min,63,sizeof(f_min)); 25 for(R i=1;i<=n;i++) 26 { 27 scanf("%s",c+1); 28 for(R j=1;j<=n;j++) 29 { 30 if(c[j] == '=' || i == j) 31 f_min[i][j] = f_max[i][j] = 0; 32 else if(c[j] == '+') 33 f_min[i][j] = 2, f_max[i][j] = 1;//s[i] - s[j] <= 2, s[i] - s[j] >= 1(最大是3 - 1 = 2) 34 else if(c[j] == '-') 35 f_min[i][j] = -1, f_max[i][j] = -2;//s[i] - s[j] <= -1, s[i] - s[j] >= -2 36 else 37 f_min[i][j] = 2, f_max[i][j] = -2;//s[i] - s[j] <= 2, i - j >= -2 38 } 39 } 40 41 } 42 #define f_min f_min 43 #define f_max f_max 44 void floyd() 45 { 46 /*for(R k=1;k<=n;k++) 47 for(R i=1;i<=n;i++) 48 { 49 if(i == k) continue;//防止自己做中转 50 for(R j=1;j<=n;j++) 51 { 52 if(i == j) continue;//自己到自己是没有用的 53 upmin(f_min[i][j], f_min[i][k] + f_min[k][j]); 54 upmax(f_max[i][j], f_max[i][k] + f_max[k][j]); 55 } 56 }*/ 57 for(int k=1;k<=n;k++) //Floyd 58 for(int i=1;i<=n;i++) 59 { 60 if(i==k) continue; 61 for(int j=1;j<=n;j++) 62 { 63 if(i==j) continue; 64 f_min[i][j]=min(f_min[i][j],f_min[i][k]+f_min[k][j]);//上界求最短路 65 f_max[i][j]=max(f_max[i][k]+f_max[k][j],f_max[i][j]);//下界求最长路 66 } 67 } 68 } 69 70 void work() 71 {//error!!!额。。。最长路对应最小值,最短路对应最大值 72 /*for(R i=1;i<=n;i++) 73 { 74 for(R j=1;j<=n;j++) 75 printf("%d ",f_min[i][j]); 76 printf(" "); 77 } 78 printf(" "); 79 for(R i=1;i<=n;i++) 80 { 81 for(R j=1;j<=n;j++) 82 printf("%d ",f_max[i][j]); 83 printf(" "); 84 }*/ 85 for(R i = 1; i <= n; i++)//强行枚举每一种可能 86 { 87 if(i == a || i == b) continue;//不能选已经选定了的 88 for(R j = 1; j < i; j++)//<i防止重复统计 89 { 90 if(j == a || j == b) continue;//同上 91 if(f_min[a][i] < f_max[j][b] || f_min[a][j] < f_max[i][b]) ++ans3; 92 if(f_max[a][i] > f_min[j][b] || f_max[a][j] > f_min[i][b]) ++ans1; 93 if(f_max[a][i] == f_min[a][i] && f_max[j][b] == f_min[j][b] && f_max[a][i] == f_max[j][b]) ++ans2; 94 else if(f_min[a][j] == f_max[a][j] && f_min[i][b] == f_max[i][b] && f_min[a][j] == f_min[i][b]) ++ans2; 95 } 96 } 97 printf("%d %d %d ",ans1,ans2,ans3); 98 } 99 100 int main() 101 { 102 freopen("in.in","r",stdin); 103 pre(); 104 floyd(); 105 work(); 106 fclose(stdin); 107 return 0; 108 }