Sunday, September 23, 2012

UVA: 10267 Programming Challenges (Skiena & Revilla) Volume-1

UVA:10267:Graphical Editor


Background- Here the judges are looking for best flood fill algorithm implementation. Initially It look very easy to code with recursion but i turned out to be nightmare for me to satisfy the judge requirement. Actually in this problem you will learn that recursion is not useful in every situation. In first attempt, I implemented 8-way flood fill recursion but on submission it was stack overflow for the worst case then switched to iterative model of flood fill with stack. Eventually I found very nice implementation of flood fill with line scan and stack that has helped me to achieve my best timing of 0.012 sec with rank 37. If the execution time can be optimize for 0.003 sec more can put this implementation on elite list of this problem. Something that is I am trying on.

C++ Implementation -

#include <iostream>
#include <iterator> 
#include <string>
#include <algorithm>
#include <sstream>
#include <stack>
#include <string.h>
using namespace std;

typedef pair<unsigned short, unsigned short> point;
unsigned short M = 250, N = 250;
char dc[251][251];
inline unsigned short  Max(unsigned short x, unsigned short y) {
    return x ^ ((x ^ y) & -(x < y));
}

inline unsigned short Min(unsigned short x, unsigned short y) {
    return y ^ ((x ^ y) & -(x < y));
}

void clear() {
    for(int i=0; i < N; i++) {
        memset(dc[i], 'O' , M);
        dc[i][M] = '\0';
    }
}

void apply_color(point& A, point& B, char C) {
    if (A == B) {
        dc[A.second][A.first] = C;
    } else if (A.first == B.first) {
        while(A.second <= B.second) {
            dc[A.second++][A.first] = C;
        }
    } else {
        while(A.second <= B.second) {
            memset(dc[A.second]+A.first, C, B.first-A.first+1);
            A.second++;
        }
    }
}

void fill_color(const point& A, char P, char C) {
    bool spanLeft, spanRight;
    stack<point> S;
    S.push(A);
    while(S.empty() == false)
    {    
        point n = S.top();
        short x, y;
        x = n.first;
        y = n.second;
        S.pop();
        while(y >= 0 && dc[y][x] == P) 
            y--;
        y++;
        spanLeft = spanRight = false;
        while(y < N && dc[y][x] == P )
        {
            dc[y][x] = C;
            if((!spanLeft) && x > 0 && dc[y][x-1] == P) {
                S.push(point(x-1, y));
                spanLeft = true;
            }
            else if(spanLeft && x > 0 && dc[y][x-1] != P) {
                spanLeft = false;
            }
            if((!spanRight) && x < M-1 && dc[y][x+1] == P) {
                S.push(point(x+1, y));
                spanRight = true;
            }
            else if(spanRight && x < M-1 && dc[y][x + 1] != P) {
                spanRight = false;
            } 
            y++;
        }
    }
}

bool process_cmd(const string& cmdline) {
    bool result = false;
    stringstream tokens(stringstream::in | stringstream::out);
    tokens << cmdline;
    char cmd, C;
    unsigned short X1,X2, Y1, Y2;
    tokens >> cmd;
    switch(cmd) {
        case 'I':
            tokens >> M >> N;
            if(M > 0 && M <= 250 && N> 0 && N <= 250)
                clear();
            else 
                M=N=0;
            break;
        case 'C':
            if(M > 0 && M <= 250 && N> 0 && N <= 250)
                clear();
            break;
        case 'L':
                tokens >> X1 >> Y1 >> C;
                X1--; Y1--;
                if(X1 < M && Y1 < N && C >= 'A' && C <= 'Z') {
                    point A(X1, Y1);
                    apply_color(A, A, C);
                }
            break;
        case 'V':
                tokens >> X1 >> Y1 >> Y2 >> C;
                X1--; Y1--; Y2--;
                if(X1 < M && Y1 < N && Y2 < N && C >= 'A' && C <= 'Z') {
                    point A(X1, min(Y1, Y2)), B(X1, max(Y1, Y2));
                    apply_color(A, B, C);
                }
            break;
        case 'H':
                tokens >> X1 >> X2 >> Y1 >> C;
                X1--; X2--; Y1--;
                if(X1 < M && X2 < M && Y1 < N && C >= 'A' && C <= 'Z') {
                    point A(min(X1, X2), Y1), B(max(X1, X2), Y1);
                    apply_color(A, B, C);
                }
            break;
        case 'K':
                tokens >> X1 >> Y1 >> X2 >> Y2 >> C;
                X1--; X2--; Y1--; Y2--;
                if(X1 < M && X2 < M && Y1 < N && Y2 < N && C >= 'A' && C <= 'Z') {
                    if(X1 > X2) swap(X1, X2);
                    if(Y1 > Y2) swap (Y1, Y2);
                    point A(X1, Y1), B(X2, Y2);
                    apply_color(A, B, C);

                }
            break;
        case 'F':
                tokens >> X1 >> Y1 >> C;
                X1--; Y1--;
                if(X1 < M && Y1 < N && C >= 'A' && C <= 'Z' && dc[Y1][X1] != C) {
                        fill_color(point(X1, Y1), dc[Y1][X1], C);
                }
            break;
        case 'S':
            {    
                string filename;
                tokens >> filename;
                cout << filename << endl;
                copy(dc, dc+N, ostream_iterator<string>(cout, "\n"));
            }
            break;
        case 'X':
            result= true;
            break;
        default:
            break;
    }
    return result;
}

/* main
 * */
int main() {
    bool exit = false;
    while ( exit == false ) {
        string cmdline;
        getline(cin, cmdline);
        exit = process_cmd(cmdline);
    }
    return 0;
}
Afterthoughts  -
  • It has been learnt that we need to handle negative test cases also in our implementation even though the judges problem statement says and promises the legitimate inputs. 
  • In this implementation if we remove check for small letter color input execution time will jump to somewhere 0.03 sec.
Give a try and do share - 

UVA: 10189 Programming Challenges (Skiena & Revilla) Volume-1

UVA:10189:Minesweeper

Background- This is very cute easy game Minesweeper, The problem here is to reveal the step on mines. It was quite a fun coding this problem and has given me a good refresh to STL c++ library. With my favorite  coding environment STL the source size is quite small and got amazing 0.012 sec timing with this implementation. Whatever rest I tried gave me time overhead. My implementations are as follows -  


Now I have Version-2 which has slightly improved performance of 0.008 sec. There is slight change in implementation, actually I am not happy with my first try. It looks like I have not given enough time on implementation, It was mistake and want to keep here so that It can remind me every time I come here.

C++ Implementation:

version -2

#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>
using namespace std;
void algorithm(string& prev, string& curr, string& res) {
    short m = curr.size()-2;
    string next(m+2, '0');
    size_t pos = 1;
    while(pos <= m) {
        if(curr[pos] == '*') {
                curr[pos+1] != '*' ? curr[pos+1] = 1 + res[pos+1]   : 0;
                curr[pos-1] != '*' ? curr[pos-1]++                  : 0;
                prev[pos]   != '*' ? prev[pos]++                    : 0;
                prev[pos+1] != '*' ? prev[pos+1]++                  : 0;
                prev[pos-1] != '*' ? prev[pos-1]++                  : 0;
                next[pos]++;
                next[pos+1]++;
                next[pos-1]++;
        } else if(curr[pos] == '.'){
            curr[pos] = res[pos];
        }
        pos++;
    }
    res = next;
}

/* main
 * */

int main() {
    long fields = 0;
    string curr;
    string prev;
    string res;
    curr.reserve(120);
    prev.reserve(120);
    res.reserve(120);
    while ( true ) {
        unsigned long n =0;
        unsigned long m =0;
        cin >> n >> m;
        if (n == 0 && m == 0) { 
            return 0;
        }
        prev= string(m+2, '0');
        res = string(m+2, '0');
        if(fields != 0) 
            cout << endl;
        fields++;
        cout << "Field #" << fields <<":" << endl;
        cin >> curr;
        curr = '0'+curr+'0';
        algorithm(prev, curr, res);
        prev = curr;
        for (short i = 1; i < n; i++) {
            cin >> curr;
            curr = '0'+curr+'0';
            algorithm(prev, curr, res);
            copy(prev.begin()+1, prev.begin()+m+1, ostream_iterator<char>(cout, ""));
            cout << endl;
            prev = curr;
        }
        copy(prev.begin()+1, prev.begin()+m+1, ostream_iterator<char>(cout, ""));
        cout << endl;
    }
}


version -1
Version - 1
#include <iostream>
#include <string>
#include <sstream>
using namespace std;
ostringstream oss;
void algorithm(string& prev, string& curr, string& res) {
    short m = curr.size();
    string next(m, '0');
    size_t pos = 0;
    while(pos < m) {
        if(curr[pos] == '*') {
            if(pos == 0) {
                curr[pos+1] != '*' ? curr[pos+1]=1 + res[pos+1]     : 0;
                prev[pos]   != '*' ? prev[pos]++                    : 0;
                prev[pos+1] != '*' ? prev[pos+1]++                  : 0;
                next[pos]++;
                next[pos+1]++;
            } else if(pos == curr.size()-1) {
                curr[pos-1] != '*' ? curr[pos-1]++                    : 0;
                prev[pos]   != '*' ? prev[pos]++                    : 0;
                prev[pos-1] != '*' ? prev[pos-1]++                  : 0;
                next[pos]++;
                next[pos-1]++;
            } else {
                curr[pos+1] != '*' ? curr[pos+1]=1  + res[pos+1]    : 0;
                curr[pos-1] != '*' ? curr[pos-1]++                    : 0;
                prev[pos]   != '*' ? prev[pos]++                    : 0;
                prev[pos+1] != '*' ? prev[pos+1]++                  : 0;
                prev[pos-1] != '*' ? prev[pos-1]++                  : 0;
                next[pos]++;
                next[pos+1]++;
                next[pos-1]++;
            }
        } else if(curr[pos] == '.'){
            curr[pos] = res[pos];
        } else {
        }
        pos++;
    }
    res = next;
}

/* main
 * */

int main() {
    long fields = 0;
    string curr;
    string prev;
    string res;
    curr.reserve(120);
    prev.reserve(120);
    res.reserve(120);
    while ( true ) {
        unsigned long n =0;
        unsigned long m =0;
        cin >> n >> m;
        if (n == 0 && m == 0) { 
            cout << oss.str();
            return 0;
        }
        prev= string().append(m, '0');
        res = string().append(m, '0');
        if(fields != 0) 
            oss << endl;
        fields++;
        oss << "Field #" << fields <<":" << endl;
        for (short i = 0; i < n; i++) {
            cin >> curr;
            algorithm(prev, curr, res);
            if(i > 0)
                oss << prev << endl;
            prev = curr;
        }
        oss << prev << endl;
    }
}


Give a try and do share-

UVA: 706 Programming Challenges (Skiena & Revilla) Volume-1

UVA:706:LC DISPLAY

Background- This is very interesting problem to code the LC Display of numbers but I had tough time match the judges requirement. Though my implementation has 0.028 sec timing and 848 rank but still I feel there is lot of scope to optimize this again interestingly people out there who managed to get this done in 0.000 sec. I am still thinking how can it be rendered in O(1) timing when it desired to render it linearly. Any way this is still a matter of work for me to figure out the way to solve it in just no time.


C++ Implementation - 

#include <iostream>
#include <string>
#include <stdio.h>
using namespace std;
char number[20];

// string table[s][n][l];
string table[10][10][5] = {
{{" - ", "| |", "   ", "| |", " - "},{
"   ", "  |", "   ", "  |", "   "},{
" - ", "  |", " - ", "|  ", " - "},{
" - ", "  |", " - ", "  |", " - "},{
"   ", "| |", " - ", "  |", "   "},{
" - ", "|  ", " - ", "  |", " - "},{
" - ", "|  ", " - ", "| |", " - "},{
" - ", "  |", "   ", "  |", "   "},{
" - ", "| |", " - ", "| |", " - "},{
" - ", "| |", " - ", "  |", " - "}
},{{
" -- ", "|  |", "    ", "|  |", " -- "},{
"    ", "   |", "    ", "   |", "    "},{
" -- ", "   |", " -- ", "|   ", " -- "},{
" -- ", "   |", " -- ", "   |", " -- "},{
"    ", "|  |", " -- ", "   |", "    "},{
" -- ", "|   ", " -- ", "   |", " -- "},{
" -- ", "|   ", " -- ", "|  |", " -- "},{
" -- ", "   |", "    ", "   |", "    "},{
" -- ", "|  |", " -- ", "|  |", " -- "},{
" -- ", "|  |", " -- ", "   |", " -- "}
},{{
" --- ", "|   |", "     ", "|   |", " --- "},{
"     ", "    |", "     ", "    |", "     "},{
" --- ", "    |", " --- ", "|    ", " --- "},{
" --- ", "    |", " --- ", "    |", " --- "},{
"     ", "|   |", " --- ", "    |", "     "},{
" --- ", "|    ", " --- ", "    |", " --- "},{
" --- ", "|    ", " --- ", "|   |", " --- "},{
" --- ", "    |", "     ", "    |", "     "},{
" --- ", "|   |", " --- ", "|   |", " --- "},{
" --- ", "|   |", " --- ", "    |", " --- "}
},{{
" ---- ", "|    |", "      ", "|    |", " ---- "},{
"      ", "     |", "      ", "     |", "      "},{
" ---- ", "     |", " ---- ", "|     ", " ---- "},{
" ---- ", "     |", " ---- ", "     |", " ---- "},{
"      ", "|    |", " ---- ", "     |", "      "},{
" ---- ", "|     ", " ---- ", "     |", " ---- "},{
" ---- ", "|     ", " ---- ", "|    |", " ---- "},{
" ---- ", "     |", "      ", "     |", "      "},{
" ---- ", "|    |", " ---- ", "|    |", " ---- "},{
" ---- ", "|    |", " ---- ", "     |", " ---- "}
},{{
" ----- ", "|     |", "       ", "|     |", " ----- "},{
"       ", "      |", "       ", "      |", "       "},{
" ----- ", "      |", " ----- ", "|      ", " ----- "},{
" ----- ", "      |", " ----- ", "      |", " ----- "},{
"       ", "|     |", " ----- ", "      |", "       "},{
" ----- ", "|      ", " ----- ", "      |", " ----- "},{
" ----- ", "|      ", " ----- ", "|     |", " ----- "},{
" ----- ", "      |", "       ", "      |", "       "},{
" ----- ", "|     |", " ----- ", "|     |", " ----- "},{
" ----- ", "|     |", " ----- ", "      |", " ----- "}
},{{
" ------ ", "|      |", "        ", "|      |", " ------ "},{
"        ", "       |", "        ", "       |", "        "},{
" ------ ", "       |", " ------ ", "|       ", " ------ "},{
" ------ ", "       |", " ------ ", "       |", " ------ "},{
"        ", "|      |", " ------ ", "       |", "        "},{
" ------ ", "|       ", " ------ ", "       |", " ------ "},{
" ------ ", "|       ", " ------ ", "|      |", " ------ "},{
" ------ ", "       |", "        ", "       |", "        "},{
" ------ ", "|      |", " ------ ", "|      |", " ------ "},{
" ------ ", "|      |", " ------ ", "       |", " ------ "}
},{{
" ------- ", "|       |", "         ", "|       |", " ------- "},{
"         ", "        |", "         ", "        |", "         "},{
" ------- ", "        |", " ------- ", "|        ", " ------- "},{
" ------- ", "        |", " ------- ", "        |", " ------- "},{
"         ", "|       |", " ------- ", "        |", "         "},{
" ------- ", "|        ", " ------- ", "        |", " ------- "},{
" ------- ", "|        ", " ------- ", "|       |", " ------- "},{
" ------- ", "        |", "         ", "        |", "         "},{
" ------- ", "|       |", " ------- ", "|       |", " ------- "},{
" ------- ", "|       |", " ------- ", "        |", " ------- "}
},{{
" -------- ", "|        |", "          ", "|        |", " -------- "},{
"          ", "         |", "          ", "         |", "          "},{
" -------- ", "         |", " -------- ", "|         ", " -------- "},{
" -------- ", "         |", " -------- ", "         |", " -------- "},{
"          ", "|        |", " -------- ", "         |", "          "},{
" -------- ", "|         ", " -------- ", "         |", " -------- "},{
" -------- ", "|         ", " -------- ", "|        |", " -------- "},{
" -------- ", "         |", "          ", "         |", "          "},{
" -------- ", "|        |", " -------- ", "|        |", " -------- "},{
" -------- ", "|        |", " -------- ", "         |", " -------- "}
},{{
" --------- ", "|         |", "           ", "|         |", " --------- "},{
"           ", "          |", "           ", "          |", "           "},{
" --------- ", "          |", " --------- ", "|          ", " --------- "},{
" --------- ", "          |", " --------- ", "          |", " --------- "},{
"           ", "|         |", " --------- ", "          |", "           "},{
" --------- ", "|          ", " --------- ", "          |", " --------- "},{
" --------- ", "|          ", " --------- ", "|         |", " --------- "},{
" --------- ", "          |", "           ", "          |", "           "},{
" --------- ", "|         |", " --------- ", "|         |", " --------- "},{
" --------- ", "|         |", " --------- ", "          |", " --------- "}
},{{
" ---------- ", "|          |", "            ", "|          |", " ---------- "},{
"            ", "           |", "            ", "           |", "            "},{
" ---------- ", "           |", " ---------- ", "|           ", " ---------- "},{
" ---------- ", "           |", " ---------- ", "           |", " ---------- "},{
"            ", "|          |", " ---------- ", "           |", "            "},{
" ---------- ", "|           ", " ---------- ", "           |", " ---------- "},{
" ---------- ", "|           ", " ---------- ", "|          |", " ---------- "},{
" ---------- ", "           |", "            ", "           |", "            "},{
" ---------- ", "|          |", " ---------- ", "|          |", " ---------- "},{
" ---------- ", "|          |", " ---------- ", "           |", " ---------- "}}};



void prepare_dc(short size, string& str) {
    for(short l = 0; l<5; l++) {
        string r;
        short i = 0;
        short sz = size;
        while(number[i] != '\0') {
            r += table[size-1][((short)number[i]-48)][l];
            if(number[i+1] != '\0')
                r += " ";
            i++;
        }
        str += r + '\n';
        sz--;
        while ((l & 0x01) != 0 && sz > 0 ) {
            str += r + '\n';
            sz--;
        }
    }
}


/* main
 * */

int main() {
    while ( true ) {
        unsigned long n =0;
        short size = 0;
        fill(number, number+10, '\0');
        cin >> size >> n;
        if (size == 0) { 
            return 0;
        }
        sprintf(number, "%lu", n);
        string str;
        prepare_dc(size, str);
        cout << str <<  endl;
    }
}


After Thoughts -  


  • The above attempt has been made to print the number's digits  line by line instead of printing each digit and moving to next. Lines of each digit having size one to ten has been precomputed to reduce the execution timing.
  • I have also tried using stream instead of using multiple cout but surprisingly it has time overhead.
  • The above implementation doesn't consider the prpreceding zeros, since judges test cases don't complain so left it as it is.
  • There is nothing special in this problem but still execution timing is a challenge.
Give it a try and do share your feedback -