洛谷題書115【データ構造1-3】集合(そして集合部分を調べます)
記事の目次 P 551親戚 P 536村村通 P 155犯人を拘留する P 892[BOI 2003]グループ P 955[NOI 2015]プログラム自動解析 P 4305[JLOI 2011]数字が重複しない P 814ファミリー図 P 1551親戚
テンプレートを検索します
いくつかの連結ブロックがありますか?道路の数は連結ブロックの数を減らします.
注意点:犯罪者と敵の敵を統合する
犯罪者xの最初の敵を一列に記録し、敵があれば、直接にxの敵を一緒にすればいいです.
最後に二つの敵が一つの部屋にいたと発見したら、その時は終了して答えを出力するしかないです.
一人を敵の敵と合併する
最後にいくつかの連結ブロックがあると判断すればいいです.
心が騒がしい問題です.まず二つの要素を離散化します.e=1なら合併します.そうでなければ記録して、最後に二つの要素が一つの連結ブロック内にあるかどうかを判断します.同じブロック内の数字はきっと同じです.
最初はscanfでタイムアウトしました.クイック読み込みに変更しました.
離散化+検索セットは文字列と下付き文字列を交換し、mapで文字列を下付き文字列に変換し、配列またはmapで下付き文字列に変換する必要があります.
テンプレートを検索します
#include
#include
#include
using namespace std;
const int N = 5e4 + 5;
int fa[N]; //
void init(int n)
{
for (int i = 1; i <= n; i++)
fa[i] = i;
}
int find(int x)
{
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void unite(int x, int y)
{
x = find(x), y = find(y);
if (x == y) return;
fa[x] = y;
}
int main(void)
{
int n, m, q;
int x, y;
scanf("%d%d%d", &n, &m, &q);
init(n);
for (int i = 0; i < m; i++) {
scanf("%d%d", &x, &y);
unite(x, y);
}
for (int i = 0; i < q; i++) {
scanf("%d%d", &x, &y);
if (find(x) == find(y)) {
cout << "Yes" << endl;
} else {
cout << "No" << endl;
}
}
return 0;
}
P 536村村通いくつかの連結ブロックがありますか?道路の数は連結ブロックの数を減らします.
#include
#include
#include
using namespace std;
const int N = 5e4 + 5;
int fa[N]; //
void init(int n)
{
for (int i = 1; i <= n; i++)
fa[i] = i;
}
int find(int x)
{
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void unite(int x, int y)
{
x = find(x), y = find(y);
if (x == y) return;
fa[x] = y;
}
int main(void)
{
int t, n, m;
int x, y;
while (scanf("%d", &n) != EOF && n) {
scanf("%d", &m);
init(n);
for (int i = 0; i < m; i++) {
scanf("%d%d", &x, &y);
unite(x, y);
}
int ans = -1;
for (int i = 1; i <= n; i++)
if (find(i) == i)
ans++;
printf("%d
", ans);
}
return 0;
}
P 155犯人を拘留する注意点:犯罪者と敵の敵を統合する
犯罪者xの最初の敵を一列に記録し、敵があれば、直接にxの敵を一緒にすればいいです.
最後に二つの敵が一つの部屋にいたと発見したら、その時は終了して答えを出力するしかないです.
#include
#include
#include
#include
using namespace std;
const int N = 1e6 + 5;
typedef long long ll;
int fa[N], foe[N]; // ,
int n, m;
struct crim{
int a, b, c;
bool operator < (const crim &y) const {
return c > y.c;
}
};
crim arr[N];
void init(int n)
{
for (int i = 1; i <= n; i++)
fa[i] = i;
}
int find(int x)
{
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void unite(int x, int y)
{
x = find(x), y = find(y);
if (x == y) return;
fa[x] = y;
}
int main(void)
{
cin >> n >> m;
init(n);
for (int i = 0; i < m; i++) {
scanf("%d%d%d", &arr[i].a, &arr[i].b, &arr[i].c);
}
sort(arr, arr + m);
int res = 0;
for (int i = 0; i < m; i++) {
//
if (find(arr[i].a) == find(arr[i].b)) {
res = arr[i].c;
break;
} else {
//
if (foe[arr[i].a] == 0) {
foe[arr[i].a] = arr[i].b;
} else {
unite(foe[arr[i].a], arr[i].b);
}
//
if (foe[arr[i].b] == 0) {
foe[arr[i].b] = arr[i].a;
} else {
unite(foe[arr[i].b], arr[i].a);
}
}
}
cout << res << endl;
return 0;
}
P 892[BOI 2003]グループ一人を敵の敵と合併する
最後にいくつかの連結ブロックがあると判断すればいいです.
#include
#include
#include
#include
using namespace std;
const int N = 1e6 + 5;
typedef long long ll;
int fa[N], foe[N]; // ,
int n, m;
void init(int n)
{
for (int i = 1; i <= n; i++)
fa[i] = i;
}
int find(int x)
{
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void unite(int x, int y)
{
x = find(x), y = find(y);
if (x == y) return;
fa[x] = y;
}
int main(void)
{
char opt;
int p, q;
cin >> n >> m;
init(n);
while (m--) {
cin >> opt >> p >> q;
if (opt == 'F') {
unite(p, q);
} else {
if (foe[p] == 0) {
foe[p] = q;
} else {
unite(foe[p], q);
}
if (foe[q] == 0) {
foe[q] = p;
} else {
unite(foe[q], p);
}
}
}
int res = 0;
for (int i = 1; i <= n; i++) {
if (find(i) == i) {
res++;
}
}
cout << res << endl;
return 0;
}
P 1595[NOI 2015]プログラム自動分析心が騒がしい問題です.まず二つの要素を離散化します.e=1なら合併します.そうでなければ記録して、最後に二つの要素が一つの連結ブロック内にあるかどうかを判断します.同じブロック内の数字はきっと同じです.
#include
#include
#include
#include
using namespace std;
const int N = 1e6 + 5;
int fa[N]; //
int xx[N], yy[N];
void init(int n)
{
for (int i = 1; i <= n; i++)
fa[i] = i;
}
int find(int x)
{
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void unite(int x, int y)
{
x = find(x), y = find(y);
if (x == y) return;
fa[x] = y;
}
int main(void)
{
int t, n;
int a, b, e;
int idx1, idx2, x, y;
cin >> t;
while (t--) {
scanf("%d", &n);
init(N - 5);
idx1 = idx2 = 1;
map<int, int> mp;
for (int i = 0; i < n; i++) {
scanf("%d%d%d", &a, &b, &e);
if (mp[a] == 0) {
x = mp[a] = idx1;
idx1++;
} else {
x = mp[a];
}
if (mp[b] == 0) {
y = mp[b] = idx1;
idx1++;
} else {
y = mp[b];
}
if (e == 1) {
unite(x, y);
} else {
xx[idx2] = x, yy[idx2] = y;
idx2++;
}
}
bool flag = 1;
for (int i = 1; i < idx2; i++) {
//cout << find(xx[i]) << " " << find(yy[i]) << endl;
if (find(xx[i]) == find(yy[i])) {
flag = 0;
break;
}
}
cout << (flag ? "YES" : "NO") << endl;
}
return 0;
}
P 4305[JLOI 2011]数字は重複しません.最初はscanfでタイムアウトしました.クイック読み込みに変更しました.
#include
#include
#include
#include
using namespace std;
const int N = 5e4 + 5;
inline int read()
{
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){
if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
return s * w;
} // C++
inline void write(int x)
{
if (x < 0) x = ~x + 1, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int a[N];
int main(void)
{
int t, n;
int idx, tt;
t = read();
while (t--) {
map<int, bool> mp;
idx = 0;
n = read();
while (n--) {
tt = read();
if (mp[tt] == 0) {
mp[tt] = 1;
a[idx++] = tt;
}
}
for (int i = 0; i < idx; i++) {
write(a[i]);
putchar(' ');
}
puts("");
}
return 0;
}
P 814ファミリースペクトル離散化+検索セットは文字列と下付き文字列を交換し、mapで文字列を下付き文字列に変換し、配列またはmapで下付き文字列に変換する必要があります.
#include
#include
#include
#include
using namespace std;
const int N = 5e4 + 5;
typedef long long ll;
int fa[N], foe[N]; // ,
int n, m;
void init(int n)
{
for (int i = 1; i <= n; i++)
fa[i] = i;
}
int find(int x)
{
if (fa[x] == x) return x;
return fa[x] = find(fa[x]);
}
void unite(int x, int y)
{
x = find(x), y = find(y);
if (x == y) return;
fa[x] = y;
}
int main(void)
{
int idx = 1;
char op;
string s, t;
string arr[N];
map<string, int> mp;
init(N - 5);
while (cin >> op && op != '$') {
if (op == '#') {
cin >> s;
if (mp[s] == 0) {
mp[s] = idx;
arr[idx++] = s;
}
} else if (op == '+') {
cin >> t;
if (mp[t] == 0) {
mp[t] = idx;
arr[idx++] = t;
}
fa[mp[t]] = mp[s];
} else {
cin >> s;
t = arr[find(mp[s])];
cout << s << " " << t << endl;
}
}
return 0;
}