T1
T559。
T2(帶權並查集)
1380。
把行和列的取值看成變數,其中行取1代表+1,列取1代表-1,為了湊x - y = c,這樣可以拿並查集來做了。
維護d[x],到根的距離,我們把邊定義為+,反向走為-。這樣就行了,如果在一個集合,那麼判斷距離是不是c。
還可以差分約束,dfs(直接遍歷一遍,遇到環就判斷).
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int n, m, k;
int p[N << 1], d[N];
int find(int x)
{
if (p[x] == x) return x;
int fa = find(p[x]);
d[x] += d[p[x]];
return p[x] = fa;
}
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n + m; i ++ ) p[i] = i;
while (k -- )
{
int x, y, c;
scanf("%d%d%d", &x, &y, &c);
y += n;
int px = find(x), py = find(y);
if (px != py)
{
p[py] = px;
d[py] = d[x] + c - d[y];
}
else if (d[y] - d[x] != c)
{
puts("No");
return 0;
}
}
puts("Yes");
return 0;
}
T3(帶權並查集,與上題類似)
換成乘。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 20010;
int p[N];
double d[N];
int n, m;
int find(int x)
{
if (p[x] == x) return x;
int fa = find(p[x]);
d[x] *= d[p[x]];
return p[x] = fa;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++ ) p[i] = i, d[i] = 1;
while (m -- )
{
int x, y, a, b;
scanf("%d%d%d%d", &x, &y, &a, &b);
int px = find(x), py = find(y);
if (px != py)
{
p[py] = px;
d[py] = d[x] * a / b / d[y];
}
else
{
if (abs(d[x] - (d[y] * b / a)) >= 1e-5)
{
puts("No");
return 0;
}
}
}
puts("Yes");
return 0;
}
T4(差分約束,不等式及相對關係->差分約束)
1129。 https://www.luogu.com.cn/problem/P2474
這個題首先要想到列舉,然而我們不知道他們之間的關係,無法判斷。求解相對關係,我們發現a+b = c+d 加法不好處理,這個等式實際上就是a - c = d - b,這樣就轉化為了求差值的範圍,其實就是差分約束。不等式是啥呢?根據給定的圖,a-b的關係就給了,floyd求差分約束就行了。最後暴力列舉判斷。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 110;
int mind[N][N], maxd[N][N];
int n, A, B;
char g[N][N];
void floyd()
{
for (int k = 1; k <= n; k ++ )
for (int i = 1; i <= n; i ++ )
for (int j = 1; j <= n; j ++ )
{
mind[i][j] = max(mind[i][j], mind[i][k] + mind[k][j]);
maxd[i][j] = min(maxd[i][j], maxd[i][k] + maxd[k][j]);
}
}
int main()
{
freopen("balance.in", "r", stdin);
freopen("balance.out", "w", stdout);
scanf("%d%d%d", &n, &A, &B);
for (int i = 1; i <= n; i ++ )
{
scanf("%s", g[i] + 1);
for (int j = 1; j <= n; j ++ )
if (i != j)
{
if (g[i][j] == '+') mind[i][j] = 1, maxd[i][j] = 2;
else if (g[i][j] == '?') mind[i][j] = -2, maxd[i][j] = 2;
else if (g[i][j] == '-') mind[i][j] = -2, maxd[i][j] = -1;
}
}
floyd();
int c1 = 0, c2 = 0, c3 = 0;
for (int i = 1; i <= n; i ++ )
for (int j = i + 1; j <= n; j ++ )
if (i != j && i != A && i != B && j != A && j != B)
{
if (mind[A][i] > maxd[j][B] || mind[A][j] > maxd[i][B]) c1 ++ ;
if ((maxd[A][i] == mind[A][i] && maxd[j][B] == mind[j][B] && mind[A][i] == maxd[j][B])
|| (maxd[A][j] == mind[A][j] && maxd[i][B] == mind[i][B] && mind[A][j] == maxd[i][B]))
c2 ++ ;
if (maxd[A][i] < mind[j][B] || maxd[A][j] < mind[i][B]) c3 ++ ;
}
printf("%d %d %d\n", c1, c2, c3);
fclose(stdin);
fclose(stdout);
return 0;
}