【洛谷】2474:[SCOI2008]天平【差分約束系統】
阿新 • • 發佈:2018-11-08
P2474 [SCOI2008]天平
題目背景
2008四川NOI省選
題目描述
你有n個砝碼,均為1克,2克或者3克。你並不清楚每個砝碼的重量,但你知道其中一些砝碼重量的大小關係。你把其中兩個砝碼A 和B 放在天平的左邊,需要另外選出兩個砝碼放在天平的右邊。問:有多少種選法使得天平的左邊重(c1)、一樣重(c2)、右邊重(c3)?(只有結果保證惟一的選法才統計在內)
輸入輸出格式
輸入格式:
第一行包含三個正整數n,A,B(1<=A,B<=N,A 和B 不相等)。砝碼編號
為1~N。以下n行包含重量關係矩陣,其中第i行第j個字元為加號“+”表示砝
碼i比砝碼j重,減號“-”表示砝碼i比砝碼j 輕,等號“=”表示砝碼i和砝碼
j一樣重,問號“?”表示二者的關係未知。存在一種情況符合該矩陣。
輸出格式:
僅一行,包含三個整數,即c1,c2和c3。
輸入輸出樣例
輸入樣例#1: 複製6 2 5 ?+???? -?+??? ?-???? ????+? ???-?+ ????-?輸出樣例#1: 複製
1 4 1
輸入樣例#2: 複製
14 8 4 ?+???++?????++ -??=?=???????= ??????????=??? ?=??+?==?????? ???-???-???-?? -=???????????? -??=???=?-+??? ???=+?=??????? ?????????????? ??????+??????? ??=???-????-?? ????+?????+??? -????????????? -=????????????輸出樣例#2: 複製
18 12 11
說明
4<=n<=50
Solution
題目要求的實際上是滿足$A+B>i+j,A+B=i+j,A+B<i+j$的所有$i,j$組合有多少組。
比如第一個式子,可以轉換為$A-i>j-B$
看上去很差分約束啊!
所以我們可以用$floyed$處理出任意兩點$i-j$的最大值和最小值,初始化賦值顯然。
然後列舉所有的$i,j$組合,判斷是否滿足不等式即可。注意滿足的條件是最小值大於最大值等等。
Code
#include<bits/stdc++.h> using namespace std; char s[66]; int dx[55][55], dn[55][55], n, A, B; int main() { scanf("%d%d%d", &n, &A, &B); memset(dx, 0x3f3f3f3f, sizeof(dx)); memset(dn, -0x3f3f3f3f, sizeof(dn)); for(int i = 1; i <= n; i ++) { scanf("%s", s + 1); for(int j = 1; j <= strlen(s + 1); j ++) { if(s[j] == '=' || i == j) { dn[i][j] = dx[i][j] = 0; } else if(s[j] == '+') { dn[i][j] = 1; dx[i][j] = 2; } else if(s[j] == '-') { dn[i][j] = -2; dx[i][j] = -1; } else { dn[i][j] = -2; dx[i][j] = 2; } } } for(int k = 1; k <= n; k ++) for(int i = 1; i <= n; i ++) for(int j = 1; j <= n; j ++) { dx[i][j] = min(dx[i][j], dx[i][k] + dx[k][j]); dn[i][j] = max(dn[i][j], dn[i][k] + dn[k][j]); } int c1 = 0, c2 = 0, c3 = 0; for(int i = 1; i <= n; i ++) { if(i == A || i == B) continue; for(int j = 1; j < i; j ++) { if(j == A || j == B) continue; if(dn[A][i] > dx[j][B] || dn[B][i] > dx[j][A]) c1 ++; if(dn[i][A] > dx[B][j] || dn[i][B] > dx[A][j]) c3 ++; if((dn[A][i] == dx[A][i] && dn[j][B] == dx[j][B] && dn[A][i] == dn[j][B]) || (dn[B][i] == dx[B][i] && dn[j][A] == dx[j][A] && dn[B][i] == dn[j][A])) c2 ++; } } printf("%d %d %d", c1, c2, c3); return 0; }