about summary refs log tree commit diff
path: root/usth/ICT2.1/final/problem2.c
blob: 1b3368df5b6ca79a4763526a41d8236366207c8e (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
 * Read one natural number from stdin and print its prime factors to stdout
 * The time complexity analysis of this program is commented in the source code
 */
#include <stdio.h>
#include <stdlib.h>

typedef struct list construct;
struct list {
	void *car;
        construct *cdr;
};

typedef struct {
	construct *stack;
} stack;

construct *cons(void *first, construct *rest)
{
	construct *list = malloc(sizeof(construct));
	list->car = first;
	list->cdr = rest;
	return list;
}

void *car(construct *list)
{
	return list->car;
}

construct *cdr(construct *list)
{
	return list->cdr;
}

stack *mkstack()
{
	stack *s = malloc(sizeof(stack));
	s->stack = NULL;
	return s;
}

int stack_empty(stack *s)
{
	return s->stack == NULL;
}

void stack_push(stack *s, void *item)
{
	s->stack = cons(item, s->stack);
}

void *stack_top(stack *s)
{
	return car(s->stack);
}

void *stack_pop(stack *s)
{
	void *first = car(s->stack);
	construct *rest = cdr(s->stack);
	free(s->stack);
	s->stack = rest;
	return first;
}

int main()
{
	int n, m;		/* Θ(1) */
	stack *s = mkstack();	/* Θ(1) */

	scanf("%d", &n);	/* Θ(1) */
	m = n;			/* Θ(1) */
	/*
	 * Let P be the sequence of prime factors of n and l be length of P.
	 * Let T(n, 2) be the time complexity of this for loop.
	 * Consider the function T(n, i):
	 *     T(n, i) = Θ(1) if i*i >= n
	 *     T(n, i) = T(n, i + 1) + Θ(1) if n is not divisible by i	(*)
	 *     T(n, i) = T(n/i, i) + Θ(1) if n is divisible by i	(**)
	 *
	 * If only the (*) recurrence occurs, it is the worst case and
	 *     T(n, 2) = sum(Θ(1) for i from 2 to floor(sqrt(n))) = Θ(sqrt(n))
	 *
	 * If only the (**) recurrence occurs, it is the best case where n
	 * is power of 2.  For convenience, we define R(n) = T(n, 2) and get
	 *     R(n) = 1R(n/2) + Θ(n^log2(1))
	 * By the master theorem,
	 *     R(n) = Θ(n^log2(1) lg(n)) = Θ(lg(n)).
	 *
	 * If both occurs (average case), I can imagine that there exist numbers
	 * n_0, n_1, etc. and m_0, m_1, etc. that
	 *     T(n, 2) = sum(Θ(sqrt(n_i))) + sum(Θ(lg(m_i))) = Θ(sqrt(n))
	 * I, however, fail to formulate a rigorous proof for this.
	 */
	for (int i = 2; i * i <= n; ++i)
		while (n % i == 0) {
			int *tmp = malloc(sizeof(int)); /* Θ(1) */
			*tmp = i;			/* Θ(1) */
			stack_push(s, tmp);		/* Θ(1) */
			n /= i;				/* Θ(1) */
		}
	if (n != 1) {
		int *tmp = malloc(sizeof(int));
		*tmp = n;
		stack_push(s, tmp);
	}	/* Θ(1) */

	/*
	 * Since each iteration of the loop above produce at most one
	 * prime factor, the time complexity of the loop below is O(T(n, 2)).
	 */
	while (!stack_empty(s)) {
		printf("%d * ", *(int *) stack_top(s));		/* Θ(1) */
		stack_pop(s);					/* Θ(1) */
	}
	/* Terrible hack, not even portable (depending on flush behavior) */
	printf("\b\b= %d\n", m);				/* Θ(1) */

	return 0;
}

/*
 * Conclusion on time complexity:
 * Best case:  Θ(lg(n)) + O(Θ(lg(n))) = Θ(lg(n))
 * Average case and worst case:  Θ(sqrt(n)) + O(Θ(sqrt(n))) = Θ(sqrt(n))
 */