العثور على سلاسل الجيران بما يصل إلى موقعين مختلفين
-
22-08-2019 - |
سؤال
بالنظر إلى سلسلة أولية، أريد العثور على جيرانها الذين يختلفون في موقعين على الأكثر.جميع الأرقام التي تنطوي عليها عملية إنشاء السلسلة هي أربعة فقط (أي:0،1،2،3).وهذا هو المثال لما أعنيه:
# In this example, 'first' column
# are neighbors with only 1 position differ.
# The rest of the columns are 2 positions differ
Seed = 000
100 110 120 130 101 102 103
200 210 220 230 201 202 203
300 310 320 330 301 302 303
010 011 012 013
020 021 022 023
030 031 032 033
001
002
003
Seed = 001
101 111 121 131 100 102 103
201 211 221 231 200 202 203
301 311 321 331 300 302 303
011 010 012 013
021 020 022 023
031 030 032 033
000
003
002
Hence given a tag of length L
we will have 3*L + 9L(L-1)/2 neighbors
ولكن لماذا يفشل هذا الكود الخاص بي في إنشائه بشكل صحيح؟خاصة عندما تكون سلسلة البذور غير ذلك "000".
كما يتم الترحيب بالطرق الأخرى، خاصة فيما يتعلق بتحسين السرعة.لأننا سنقوم بمعالجة ملايين علامات البذور من 34 إلى 36.
#include <iostream>
#include <vector>
#include <fstream>
#include <sstream>
using namespace std;
string ConvertInt2String(int IntVal) {
std::string S;
std::stringstream out;
out << IntVal;
S = out.str();
return S;
}
string Vec2Str (vector <int> NTg) {
string StTg = "";
for (unsigned i = 0; i < NTg.size(); i++) {
StTg += ConvertInt2String(NTg[i]);
}
return StTg;
}
template <typename T> void prn_vec(const std::vector < T >&arg, string sep="")
{
for (unsigned n = 0; n < arg.size(); n++) {
cout << arg[n] << sep;
}
return;
}
vector <int> neighbors(vector<int>& arg, int posNo, int baseNo) {
// pass base position and return neighbors
vector <int> transfVec;
transfVec = arg;
//modified according to strager's first post
transfVec[posNo % arg.size()] = baseNo;
return transfVec;
}
int main () {
vector <int> numTag;
numTag.push_back(0);
numTag.push_back(0);
numTag.push_back(1); // If "000" this code works, but not 001 or others
// Note that in actual practice numTag can be greater than 3
int TagLen = static_cast<int>(numTag.size());
for ( int p=0; p< TagLen ; p++ ) {
// First loop is to generate tags 1 position differ
for ( int b=1; b<=3 ; b++ ) {
int bval = b;
if (numTag[p] == b) {
bval = 0;
}
vector <int> nbnumTag = neighbors(numTag, p, bval);
string SnbnumTag = Vec2Str(nbnumTag);
cout << SnbnumTag;
cout << "\n";
// Second loop for tags in 2 position differ
for (int l=p+1; l < TagLen; l++) {
for (int c=1; c<=3; c++) {
int cval = c;
if (nbnumTag[l] == c) {
cval = c;
}
vector <int> nbnumTag2 = neighbors(nbnumTag, l, cval);
string SnbnumTag2 = Vec2Str(nbnumTag2);
cout << "\t" << SnbnumTag2;
cout << "\n";
}
}
}
}
return 0;
}
المحلول
هل هذا سيفعل ذلك؟يقوم بتعداد شجرة السلاسل المحتملة، مع تقليمها جميعًا بفارق أكبر من 2 عن النص الأصلي.
void walk(char* s, int i, int ndiff){
char c = s[i];
if (ndiff > 2) return;
if (c == '\0'){
if (ndiff > 0) print(s);
}
else {
s[i] = '0'; walk(s, i+1, (s[i]==c ? ndiff : ndiff+1);
s[i] = '1'; walk(s, i+1, (s[i]==c ? ndiff : ndiff+1);
s[i] = '2'; walk(s, i+1, (s[i]==c ? ndiff : ndiff+1);
s[i] = '3'; walk(s, i+1, (s[i]==c ? ndiff : ndiff+1);
s[i] = c;
}
}
char seed[] = "000";
main(){
walk(seed, 0, 0);
}
نصائح أخرى
إليك إحدى الطرق للقيام بذلك والتي يجب أن تعمل مع أي عدد من الأحرف وطول السلسلة:
string base = "000";
char values[] = {'0', '1', '2', '3' };
for (int i = 0; i < base.length(); ++i)
{
for (int j = 0; j < countof(values); ++j)
{
if (base[i] != values[j])
{
string copy = base;
copy[i] = values[j];
cout << copy << endl;
for (int k = i+1; k < base.length(); ++k)
{
for (int l = 0; l < countof(values); ++l)
{
if (copy[k] != values[l])
{
string copy2 = copy;
copy[k] = values[l];
cout << copy2 << endl;
}
}
}
}
}
}
يجب أن يكون هذا معادلاً لتوليد جميع السلاسل ضمن مسافة هام 2، عبر أبجدية مكونة من 4 رموز.لقد رأيت خوارزميات لذلك، لكنني في حيرة من أمر العثور عليها الآن.وربما يكون هذا بمثابة مؤشر في الاتجاه الصحيح.
مشكلتك [يحرر:النسخة الأصلية (انظر المراجعات السابقة للسؤال)] هو أنه في حلقتك الداخلية، تقوم فقط بتعيين العنصر "التالي".الحل السريع هو التفاف الكتابة neighbors
:
vector <int> neighbors(const vector<int>& arg, int posNo, int baseNo) {
// pass base position and return neighbors
vector <int> transfVec = arg
transfVec[posNo % arg.size()] = baseNo;
return transfVec;
}
يعمل هذا الإصلاح فقط عندما يكون لديك عنصرين أو ثلاثة عناصر في المصفوفة الخاصة بك.إذا كنت تريد المزيد، فأنت بحاجة إلى إعادة كتابة الخوارزمية الخاصة بك لأنها لا تتعامل مع الحالات التي يكون فيها الطول أكبر من ثلاثة على الإطلاق.(لا ينبغي أن تحتاج إلى ذلك، حتى.الخوارزمية التي تستخدمها مقيدة للغاية.)
هذين إذا كان:
if (numTag[p] == b) {
bval = 0;
}
if (nbnumTag[l] == c) {
cval = c;
}
ينبغي بدلا من ذلك أن يكون جثث continue
.
يجب أن تبدأ هاتان الحلقتان عند 0:
for ( int b=1; b<=3 ; b++ ) {
for (int c=1; c<=3; c++) {
// i.e.
for ( int b=0; b<=3 ; b++ ) {
for (int c=0; c<=3; c++) {
يبدو أن ستراجر قد حدد المشكلة الرئيسية:شروط الحلقة.الأبجدية الخاصة بك هي 0،1،2،3، لذا يجب عليك تكرار هذا النطاق بأكمله.0 ليست حالة خاصة، حيث يحاول الكود الخاص بك التعامل معها.الحالة الخاصة هي تخطي التكرار عندما تساوي القيمة الأبجدية القيمة الموجودة في مفتاحك، وهو ما تحققه المتابعة التي يقترحها Strager.
فيما يلي نسختي من الخوارزمية الخاصة بك.لديه بعض الأفكار البديلة لهياكل الحلقة، ويتجنب نسخ المفتاح عن طريق تعديله في مكانه.لاحظ أنه يمكنك أيضًا تغيير حجم الحروف الأبجدية عن طريق تغيير MIN_VALUE
و MAX_VALUE
الثوابت.
إليك إخراج الحالة "001":
101 111 121 131 102 103 100
201 211 221 231 202 203 200
301 311 321 331 302 303 300
011 012 013 010
021 022 023 020
031 032 033 030
002
003
000
وهذا هو الكود:
#include <iostream>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
const int MIN_VALUE = 0;
const int MAX_VALUE = 3;
int increment(int& ch)
{
if (ch == MAX_VALUE)
ch = MIN_VALUE;
else
++ch;
return ch;
}
string stringKey(const vector<int>& key)
{
ostringstream sout;
for (int i = 0; i < key.size(); ++i)
sout << key[i];
return sout.str();
}
int main()
{
vector<int> key;
key.push_back(0);
key.push_back(0);
key.push_back(1);
for (int outerKeyPos = 0; outerKeyPos < key.size(); ++outerKeyPos)
{
int outerOriginal = key[outerKeyPos];
while (increment(key[outerKeyPos]) != outerOriginal)
{
cout << stringKey(key);
for (int innerKeyPos = outerKeyPos + 1; innerKeyPos < key.size(); ++innerKeyPos)
{
int innerOriginal = key[innerKeyPos];
while (increment(key[innerKeyPos]) != innerOriginal)
{
cout << " " << stringKey(key);
}
}
cout << endl;
}
}
}
لقد حاولت تصحيح الخوارزمية الخاصة بك، مع البقاء أقرب ما يمكن إلى الخوارزمية الأصلية:
int TagLen = static_cast<int>(numTag.size());
for ( int p=0; p< TagLen ; p++ ) {
// First loop is to generate tags 1 position differ
for ( int b=0; b<=3 ; b++ ) { // Loop over all 4 elements
int bval = b;
if (numTag[p] == b) {
continue; // This is the seed vector, ignore it
}
vector <int> nbnumTag = neighbors(numTag, p, bval);
string SnbnumTag = Vec2Str(nbnumTag);
cout << SnbnumTag;
cout << "\n";
// Second loop for tags in 2 position differ
for (int l=p+1; l < TagLen; l++) {
for (int c=0; c<=3; c++) {
int cval = c;
if (nbnumTag[l] == c) { // Loop over all 4 elements
continue; // This is nbnumTag, ignore it
}
vector <int> nbnumTag2 = neighbors(nbnumTag, l, cval);
string SnbnumTag2 = Vec2Str(nbnumTag2);
cout << "\t" << SnbnumTag2;
cout << "\n";
}
}
}
}
المشكلة هي أنك لا تكرر جميع القيم الأربع المحتملة (0،1،2،3)، ولكنك تتخطى 0 لسبب ما.الطريقة التي أفعل بها ذلك هي التكرار عليها جميعًا وتجاهل (باستخدام الاستمرار) المتجه الذي هو نفسه مع البذرة أو العلامة المختلفة ذات النقطة الواحدة المحسوبة في المرحلة 1.
بعد قولي هذا، أعتقد أنه تم اقتراح خوارزميات أفضل من خوارزمياتك وسيكون من الأفضل التفكير في واحدة منها.
إليكم الحل القبيح والمبتكر:
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
struct tri
{
tri(int a, int b, int c)
{
switch (a)
{
case 0:
m[0] = 0;
m[1] = b;
m[2] = c;
break;
case 1:
m[0] = b;
m[1] = 0;
m[2] = c;
break;
case 2:
m[0] = b;
m[1] = c;
m[2] = 0;
break;
}
}
int m[3];
};
int main()
{
vector<tri> v;
for (int i = 0; i < 3; i++)
for (int j = 0; j < 4; j++)
for (int k = 0; k < 4; k++)
{
v.push_back(tri(i,j,k));
}
vector<tri>::iterator it;
for (it = v.begin(); it != v.end(); ++it)
{
cout << (*it).m[0];
cout << (*it).m[1];
cout << (*it).m[2];
cout << endl;
}
}