Algorithm/미분류2012. 7. 3. 10:52

Warshall 알고리즘은 그래프에서


한 노드에서 다른 노드까지의 도달 가능성을 알아보는 알고리즘이다.


시간복잡도는 O(n^3)이다.






이 알고리즘은 인접 행렬을 사용한다.


위의 그래프를 인접 행렬로 나타내면




위의 표와 같다.


위 표는 다음과 같이 해석한다.


표[x, y]  :  (x행 y열), x 노드에서 y노드로 진행 가능함을 뜻함


ex) 1노드에서 3노드로 진행 가능, 1노드에서 5노드로 진행 불가


이 표에 warshall 알고리즘을 적용하면 다음과 같이 나타낼 수 있다.




1 노드에서는 3, 4, 5 노드로 진행 가능하며

2 노드에서는 1, 3, 4, 5 노드로 진행 가능하며

3 노드는 어느 노드로도 진행 할 수 없고

4 노드는 오직 5 노드로만 진행 가능하며

5 노드는 어느 노드로도 진행 할 수 없음을 뜻한다.


알고리즘을 대략적으로 설명하면


x -> y로의 진행이


x -> y로의 직접적인 진행이 가능하거나

x -> k -> y로의 우회적인 진행이 가능한지를 살펴보는 것이다.


덜 대략적으로 설명하면


초기 인접행렬을 M0라고 하고

M1을 x에서 y로 하나의 노드를 경유하는 경우라고 놓으면


M1[x, y] 는 M0[x, y]가 1이면 다른 노드를 경유하지 않고도 x에서 y로 갈 수 있음을 말하고

M0[x, k]와 M0[k, y]가 1이면 k 노드를 경유하여 x에서 y로 갈 수 있음을 말한다.

이걸 m0에서 m(n-1)까지

반복하면

x에서 노드를 0~n-1개 경유하여 y로 갈 수 있는지를 알 수 있다.


따라서 프로그램적으로 적어보면

M[x][y] = M[x][y] | (M[i][k] & M[k][j])

로 나타낼 수 있다.


함수를 쓰면 다음과 같다.


void warshall()

{

int i, j, k;


for (k = 0; k < n; ++k)

{

for (i = 1; i <=n; ++i)

{

for (j = 1; j <=n; ++j)

{

ar[i][j] = ar[i][j] | (ar[i][k + 1] & ar[k + 1][j]);

}

}

}

}


이 알고리즘과 관련하여 풀 수 있는 문제들...


키 순서(초4)/koi_stature


구슬 찾기/bead

'Algorithm > 미분류' 카테고리의 다른 글

LevenshtainDistance  (0) 2012.06.27
순열나열 (Permutation)  (0) 2012.06.26
Posted by 투명테잎
Algorithm/미분류2012. 6. 27. 12:37

LevenshtainDistance는 두 문자열간의 유사성을 측정하기 위해 사용된다.

spell checking, DNA 유사성 검사, 음성인식, handwriting 인식 등에 사용된다고한다.


이론적인 내용은 위키피디아에서 찾아볼 수 있다.

LevenshtainDistance




코드...



#include <iostream>

#include <cstring> // strlen 사용

using namespace std;


class LevenshtainDistance

{

private:

static int min(int a, int b, int c);

public:

static int LD(char *s, char *t);

};

int LevenshtainDistance::min(int a, int b, int c)

{

int m = a;

if (b < m) m = b;

if (c < m) m = c;

return m;

}

int LevenshtainDistance::LD(char *s, char *t)

{

int slen = strlen(s), tlen = strlen(t);

int i, j;

int cost;

int **d = new int*[slen + 1];


for (i = 0; i <= slen; ++i) d[i] = new int[tlen + 1];

if (slen == 0) return tlen;

if (tlen == 0) return slen;


for (i = 0; i <= slen; ++i) d[i][0] = i;

for (i = 0; i <= tlen; ++i) d[0][i] = i;


for (i = 1; i <= slen; ++i)

{

for (j = 1; j <= tlen; ++j)

{

if (s[i - 1] == t[j - 1]) cost = 0;

else cost = 1;

d[i][j] = min(d[i - 1][j] + 1,

d[i][j - 1] + 1,

d[i - 1][j - 1] + cost);

}

}

int dis = d[slen][tlen];

for (i = 0; i <= slen; ++i)

delete d[i];

delete d;


return dis;

}


int main()

{

char *s = "GUMBO";

char *t = "GAMBOL";

cout << LevenshtainDistance::LD(s, t) << endl;

return 0;

}


코드 출처 : 실생활 문제로 접근하는 자료구조와 알고리즘 - 김종현 [내하출판사]

'Algorithm > 미분류' 카테고리의 다른 글

Warshall 알고리즘  (0) 2012.07.03
순열나열 (Permutation)  (0) 2012.06.26
Posted by 투명테잎
Algorithm/미분류2012. 6. 26. 15:59

1부터 n까지

혹은

n부터 1까지 

나열된 일련의 숫자를


오름차순

혹은

내림차순으로 나열하는 알고리즘이다.


ex)

123

132

213

231

312

321


재귀함수는 사용하지 않았으므로

숫자가 크면 시간은 오래걸리겠지만

스택 오버플로우는 걱정 안해도 될거 같다.


c++로 작성


#include <iostream>
#include <vector>
#include <algorithm> // for swap()
using namespace std;

class Permutation
{
private:
	int n; // 원소 개수
	vector<int> v;
	bool isAsc; // true : 오름차순으로 진행?

public:
	void assign()
	{
		int i;
		v.reserve(n);
		for (i = 0; i < n; ++i)
		{
			if (isAsc)
				v.push_back(i + 1);
			else
				v.push_back(n - i);
		}
	}

	Permutation(bool asc)
	{
		cout << "Input n : ";
		cin >> n;
		isAsc = asc;
		assign();
	}

	Permutation(int num, bool asc = true)
	{
		n = num;
		isAsc = asc;
		assign();
	}

	// 오름차순일때 사용
	bool next()
	{
		if (isAsc)
		{
			int k, j, r, s;
			k = n - 2;
			while (v[k] > v[k + 1])
			{
				if (k == 0)
					return false;
				k--;
			}

			j = n - 1;

			while (v[k] > v[j]) j--;
			swap(v[j], v[k]);

			r = n - 1;
			s = k + 1;

			while (r > s)
				swap(v[r--], v[s++]);
			return true;
		}
		return false;
	}

	// 내림차순 일때 사용
	bool previous()
	{
		if (!isAsc)
		{
			int k, j, r, s;
			k = n - 2;
			while (v[k] < v[k + 1])
			{
				if (k == 0)
					return false;
				k--;
			}
			j = n - 1;

			while (v[k] < v[j]) j--;
			swap(v[j], v[k]);

			r = n - 1;
			s = k + 1;

			while (r > s)
				swap(v[r--], v[s++]);
			return true;
		}
		return false;
	}

	// 출력
	void print()
	{
		int i;
		for (i = 0; i < n; ++i)
			cout << v[i];
		cout << endl;
	}

	void fullprint()
	{
		if (isAsc)
		{
			for (; next(); )
				print();
		}
		else
			for (; previous(); )
				print();

	}
};

int main()
{
	Permutation p1(4), p2(5, false);

	cout << "----- 오름차순 순열 -----" << endl;
	p1.print();
	for (; p1.next(); )
		p1.print();

	cout << endl << "----- 내름차순 순열 -----" << endl;
	p2.fullprint();
	return 0;
}



'Algorithm > 미분류' 카테고리의 다른 글

Warshall 알고리즘  (0) 2012.07.03
LevenshtainDistance  (0) 2012.06.27
Posted by 투명테잎