P1892 [BOI2003]團夥
阿新 • • 發佈:2018-05-25
clu clas for mes lse 是我 cin 慢慢 個數
P1892 [BOI2003]團夥
題目描述
1920年的芝加哥,出現了一群強盜。如果兩個強盜遇上了,那麽他們要麽是朋友,要麽是敵人。而且有一點是肯定的,就是:
我朋友的朋友是我的朋友;
我敵人的敵人也是我的朋友。
兩個強盜是同一團夥的條件是當且僅當他們是朋友。現在給你一些關於強盜們的信息,問你最多有多少個強盜團夥。
輸入輸出格式
輸入格式:
輸入文件gangs.in的第一行是一個整數N(2<=N<=1000),表示強盜的個數(從1編號到N)。 第二行M(1<=M<=5000),表示關於強盜的信息條數。 以下M行,每行可能是F p q或是E p q(1<=p q<=N),F表示p和q是朋友,E表示p和q是敵人。輸入數據保證不會產生信息的矛盾。
輸出格式:
輸出文件gangs.out只有一行,表示最大可能的團夥數。
輸入輸出樣例
輸入樣例#1:6
4
E 1 4
F 3 5
F 4 6
E 1 2
輸出樣例#1:
3
先說一下思路:
對於只有朋友信息的數據就不用說了。對於敵人的信息,我們可以給每一個人i設置一個敵人集合E[i],當輸入i和j時,我們就把i和E[j]合並,把j和E[i]合並。
值得一提的是,要註意空集的處理,所謂空集就是一開始的時候,每個人都沒有敵人。
昨天晚上做了一晚上卡在了50分,今天又接著來啃,問同學,同學說我的想法很對,叫我自己慢慢調(WCNM我要是調的出來就不找你了)
沒辦法,慢慢找嘍。
先給大家看看我的50分的代碼。
#include <iostream> #include <cstdio> using namespace std; int n, m, Ans, x, y; int f[1008], E[1008]; char C; bool vis[1008]; int find(int x) { if(x == f[x]) return f[x]; else return f[x] = find(f[x]); } int main() { scanf("%d%d", &n, &m); for(int i=1; i<=n; i++) f[i] = i; for(int i=1; i<=m; i++) { cin>>C>>x>>y; int xx, yy; if(C == ‘E‘) { if(E[x] != 0) { f[y] = find(E[x]); } if(E[y] != 0) { f[x] = find(E[y]); } E[x] = y, E[y] = x; } if(C == ‘F‘) { f[x] = find(y); } } for(int i=1; i<=n; i++) { if(!vis[find(i)]) { vis[find(i)] = 1; Ans++; } } printf("%d", Ans); }
不知道大家看出什麽問題了沒。
沒看出的同學可要小心了,
看一下我的合並集合時候的操作,是不是把之前合並好的集合都打亂了。
為什麽?因為我合並時修改的是f[x]的值,而不是f[find(x)]的值,這就會導致很可怕的錯誤。
往後的此類操作都是這樣的。
好了,說到這裏該放上AC的代碼了
#include <iostream>
#include <cstdio>
using namespace std;
int n, m, Ans, x, y;
int f[1008], E[1008];
char C;
bool vis[1008];
int find(int x) {
if(x == f[x]) return x;
else return f[x] = find(f[x]);
}
int main() {
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++) f[i] = i;
for(int i=1; i<=m; i++) {
cin>>C>>x>>y;
if(C == ‘E‘) {
if(E[x] != 0) {
f[find(y)] = find(E[x]);
}
else E[x] = find(y);
if(E[y] != 0) {
f[find(x)] = find(E[y]);
}
else E[y] = find(x);
}
if(C == ‘F‘) {
f[find(x)] = find(y);
}
}
for(int i=1; i<=n; i++) {
if(!vis[find(i)]) {
vis[find(i)] = 1;
Ans++;
}
}
printf("%d", Ans);
}
P1892 [BOI2003]團夥