Я работаю над двудольным тестом для неориентированных графов, используя представление списка смежности. Пользователь вводит узлы и то, к чему они подключаются, причем каждая линия представляет собой пару. Например:
0 1
2 3
1 2
0 3
означает, что 0 связан с 1 и 3, 2 связан с 1 и 3, и т. д. Алгоритм выполняет BFS, раскрашивая узлы по ходу и проверяя, может ли он быть двудольным. В дополнение к просмотру, является ли график двудольным, он хранит и выводит, какие узлы принадлежат какой группе в отсортированном порядке. Следуя предыдущему примеру, 1 и 3 будут в группе A, 2 и 0 будут в группе B. Пример выходных данных будет:
Group A:
0
2
Group B:
1
3
Насколько я могу судить, текущий алгоритм работает отлично, практически без проблем, за исключением нескольких «грязных» битов кода, которые можно было бы почистить. Вот вся программа:
#include <iostream>
#include<vector>
#include<queue>
#include<map>
#include<list>
#include<algorithm>
#include<set>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
vector<int>vec[50];
map<int,int>color;
queue<int>q;
vector<int> B;
vector<int> H;
bool check(int n, int src){
q.push(src);
int i;
color[src]=1;
while(!q.empty()){
src = q.front();
q.pop();
for(i=0;i<vec[src].size();i++){
if(color[vec[src][i]]==-1){ //vec[src][i] = data; color[src] = color;
color[vec[src][i]]= 1 - color[src];
q.push(vec[src][i]);
if (color[src] == 0
and find(B.begin(), B.end(), vec[src][i]) == B.end()
and find(H.begin(), H.end(), vec[src][i]) == H.end()){
B.push_back(vec[src][i]); }
else if (color[src] == 1
and find(B.begin(), B.end(), vec[src][i]) == B.end()
and find(H.begin(), H.end(), vec[src][i]) == H.end()){
H.push_back(vec[src][i]); }
}
else if(color[vec[src][i]]== color[src]){
return 0; }
else{
if(find(B.begin(), B.end(), vec[src][i]) != B.end()){
break; }
else if(find(H.begin(), H.end(), vec[src][i]) != H.end()){
break; }
else{ B.push_back(vec[src][i]); }
}
}
}
return 1;
}
int distinct(const vector<int>& v){
set<int> distinct_container;
for(auto curr_int = v.begin(), end = v.end(); curr_int != end; ++curr_int){
distinct_container.insert(*curr_int); }
return distinct_container.size();
}
int main() {
int inp; int index = 0; vector<int> Input;
while (cin >> inp){
Input.push_back(inp); }
int points = distinct(Input);
while(index < points){
color[index]= - 1; index++; }
index = 0;
while(index < Input.size()){
vec[Input[index]].push_back(Input[index + 1]);
vec[Input[index + 1]].push_back(Input[index]);
index += 2;
}
bool res = 1; index = 0;
for(int i = 0; i < points; i++){
if(color[i]==-1){
res = res && check(points, i); }
}
if(res){
sort(B.begin(), B.end());
sort(H.begin(), H.end());
cout << "Group A:\n"; int x = 0;
while (x < B.size()){
cout << B[x] << "\n"; x++; }
cout << "Group B:\n"; int y = 0;
while (y < H.size()){
cout << H[y] << "\n"; y++; }
}
else{
cout << "IMPOSSIBLE"; }
return 0;
}
Теперь проблема в том, что мне нужно преобразовать узлы, чтобы в качестве данных использовалась строка, а не целое число. Вместо того, чтобы соединять числа, такие как 1 и 2, я хочу соединить имена, такие как Джейн и Фрэнк, следуя тому же синтаксису ввода, что и в предыдущем примере: один пробел между ними указывает на соединение. Все еще тестируем узлы, если они двухпартийные, окрашивая их в поиске, добавляя их к векторам для последующего вывода в соответствующие группы. Все, что меняется, — это тип данных ввода. И я не добился прогресса в моих попытках.
Любая помощь будет принята с благодарностью. Я в основном ищу исправления для типов данных, но я приму критику и рекомендации по любому из них. Пожалуйста, дайте мне что-нибудь еще для работы. Заранее спасибо.
Отредактируйте: следуя идее, изложенной мне Краскевичем, я думаю, что у меня все получится. Но я столкнулся с двумя новыми проблемами: собрать карты вместе в конце, чтобы вывести имена, и текущий алгоритм, независимо от ввода, возвращает IMPOSSIBLE.
Новый код: изменено только основное, и дополнительные глобальные объявления большего числа векторов.
map<string, int> toNum;
vector<string> numToString;
vector<int> BN;
vector<int> HN;
vector<string> BS;
vector<string> HS;
................
int main(){
string s; vector<int> Input; int edges = 0;
while (cin >> s){
edges++; }
int id; int index = 0; int points = 0;
if (toNum.find(s) != toNum.end()){
id = toNum[s]; }
else{
numToString.push_back(s);
toNum.insert( pair<int, string>(numToString.size() - 1, s));
id = numToString.size() - 1; ++points;
Input.push_back(id); }
while(index < points){
color[index]= - 1; index++; }
index = 0;
while(index < numToString.size()){
vec[Input[index]].push_back(Input[index + 1]);
vec[Input[index + 1]].push_back(Input[index]);
index += 2;
}
bool res = 1; index = 0;
for(int i = 0; i < points; i++){
if(color[i]==-1){
res = res && check(points, i); }
}
if(res){
index = 0; int key = 0; string name;
while (index < BN.size()){
name = toNum[BN[index]];
BS.push_back(name);
index++; }
index = 0;
while (index < HN.size()){
name = toNum[BN[index]];
HS.push_back(name);
index++; }
sort(BS.begin(), BS.end());
sort(HS.begin(), HS.end());
cout << "GROUP A\n"; int x = 0;
while (x < BS.size()){
cout << BS[x] << "\n"; x++; }
cout << "GROUP B\n"; int y = 0;
while (y < HS.size()){
cout << HS[y] << "\n"; y++; }
}
else{
cout << "IMPOSSIBLE"; }
return 0;
}
Я бы не стал менять реализацию в ширину первого поиска. Вместо этого вы можете просто сопоставить все строки с числами, запустить существующую реализацию, и они отобразят номера обратно в строки.
Как подготовить отображение? Что-то вроде того:
// A mapping from strings to their ids.
std::map<std::string, int> toNum;
// A mapping from ids to strings.
std::vector<std::string> numToString;
...
std::string s;
std::cin >> s;
int id;
if (toNum.find(s) != toNum.end()) {
id = toNum[s];
} else {
numToString.push_back(s);
id = numToString.size() - 1;
toNum[s] = id;
}