TopCoder Practices: NotchedWoodBarsPuzzle

I cannot figure out any better solution, for the 500-point problem in practice room "TCO06 Championship Round. It marked the code I pasted below only 150 point, maybe it takes the time difference between my openning the problem and my submission into consideration, and the answer is surely a bit lengthy. The merit of the program is it deals with no overlapped cases.

As the problem statement is legally claimed to be the property of topcoder, I will not post it here. However, the test set is used in the program.

The rest of this article is the code.

#include <vector>

#include <string>

using namespace std;

class NotchedWoodBarsPuzzle
{
protected:
    struct Bar
    {
        vector<int>    val;
        bool        sym;

        bool operator< (const Bar &other) const
        {
            for (int i = 0; i < val.size(); i++)
            {
                if (val[i] < other.val[i])
                {
                    return true;
                }
                else if (val[i] > other.val[i])
                {
                    return false;
                }
            }
            return false;
        }

        bool operator== (const Bar &other) const
        {
            for (int i = 0; i < val.size(); i++)
            {
                if (val[i] != other.val[i])
                {
                    return false;
                }
            }
            return true;
        }

        void Normalize ()
        {
            int k = val.size();
            bool switching = false;
            sym = true;
            for (int i = 0; i*2 < k; )
            {
                int j = k - i - 1;
                if (switching)
                {
                    int temp = val[i];
                    val[i] = val[j];
                    val[j] = temp;
                    i++, j++;
                }
                else if (val[i] > val[j])
                {
                    switching = true;
                    sym = false;
                }
                else if (val[i] < val[j])
                {
                    sym = false;
                    break;
                }
                else
                {
                    i++, j++;
                }
            }
        }
    };

    typedef vector<Bar>        BarVec;

    int     count;
    int        k2;
    int        k;
    BarVec    barvec;


    bool Check (vector<int> barsel, const vector<int> &bardesel, const vector<bool> &reverse)
    {
        vector<int>    matched(k, -1);
        vector<bool>    revs(k);
        int i, j, t;

        for (i = 0; i < k; i++)
        {
            bool has_match = false;
            for (j = 0; j < k; j++)
            {
                if (matched[j] == -1)
                {
                    matched[j] = i;
                    for (t = 0; t < k; t++)
                    {
                        int p = reverse[t]? k-i-1 : i;
                        if (barvec[barsel[t]].val[p] + barvec[bardesel[j]].val[t] != 1)
                        {
                            matched[j] = -1;
                            break;
                        }
                    }
                    if (matched[j] != -1)
                    {
                        revs[j] = false;
                        has_match = true;
                        break;
                    }

                    matched[j] = i;
                    for (t = 0; t < k; t++)
                    {
                        int p = reverse[t]? k-i-1 : i;
                        if (barvec[barsel[t]].val[p] + barvec[bardesel[j]].val[k-t-1] != 1)
                        {
                            matched[j] = -1;
                            break;
                        }
                    }
                    if (matched[j] != -1)
                    {
                        revs[j] = true;
                        has_match = true;
                        break;
                    }
                }
            }
            if (!has_match)
            {
                return false;
            }
        }

        return true;
    }

    void Deploy (vector<int> barsel, const vector<int> &bardesel, int verdict)
    {
        vector<int> dir(k, 0);
        vector<bool> reverse(k,false);
        bool finished = false;
       
        for ( ; !finished ; )
        {
            // check

            if (Check(barsel, bardesel, reverse))
            {
                count++;
            }

            // inc
            int j = k - 1;
            while (1)
            {
                if (barvec[barsel[j]].sym)
                {
                    if (j == 0)
                    {
                        finished = true; break;
                    }
                    j--;
                    continue;
                }
                dir[j]++;
                // switch
                reverse[j] = !reverse[j];

                if (dir[j] == 1) break;
                dir[j] = 0;
                j--;
                if (j == 0 && verdict == 0)
                {
                    finished = true; break;
                }
                else if (j < 0)
                {
                    finished = true; break;
                }
            }
        }
    }

    void Permute (vector<int> barsel, const vector<int> &bardesel)
    {
        /* embed order generator here */
       
        vector<int> ref(k, k-1);
        int         cur = k-2;
        bool        finished = false;
        int         verdict;
        int         i, t, left, right;

        verdict=0;
        for ( left = 0, right = k - 1; left < right; left++, right--)
        {
            if (barvec[barsel[left]] < barvec[barsel[right]])
            {
                verdict=-1;
                break;
            }
            else if (barvec[barsel[right]] < barvec[barsel[left]])
            {
                verdict=1;
                break;
            }
        }

        while (1)
        {
            // process
            Deploy(barsel, bardesel, verdict);

            // inc
__next:
            while (ref[cur] == cur)
            {
                if (cur == 0)
                {
                    finished = true;
                    break;
                }
                cur--;
            }
            if (finished)
            {
                break;
            }
           
            i = ref[cur]--;
            while (barvec[barsel[cur]]==barvec[barsel[i]])
            {
                if (ref[cur] == cur)
                {
                    goto __next;
                }
                i = ref[cur]--;
            }
           
            t = barsel[i];
            barsel[i] = barsel[cur];
            barsel[cur] = t;

            left = cur + 1;
            right = k - 1;
            for ( ; left <= right; left++, right--)
            {
                t = barsel[left];
                barsel[left] = barsel[right];
                barsel[right] = t;
                ref[left] = ref[right] = k-1;
            }
            cur = k-2;

            verdict=0;
            for ( left = 0, right = k - 1; left < right; left++, right--)
            {
                if (barvec[barsel[left]] < barvec[barsel[right]])
                {
                    verdict=-1;
                    break;
                }
                else if (barvec[barsel[right]] < barvec[barsel[left]])
                {
                    verdict=1;
                    break;
                }
            }
            if (verdict == 1)
            {
                goto __next;
            }
        }
    }

    void Separate ()
    {
        vector<int>        barsel(k);
        vector<int>     bardesel(k);
        vector<int>        barcode(k2);
        int setcode = 0;
        int i,j;
        int base = 0;
        for ( i = 0; i < k; i++ )
        {
            barsel[i] = i;

            if (i > 0 && !(barvec[i] == barvec[i-1]))
            {
                base++;
            }

            setcode += base;
        }

        base = 0;
        int totalcode = 0;
        int halfcode = 0;
        for ( i = 0; i < k2; i++ )
        {
            if (i > 0 && !(barvec[i] == barvec[i-1]))
            {
                base++;
            }
            barcode[i] = base;
            totalcode += base;
        }
        halfcode = totalcode / 2;
        // the above and the two condition judgements following in the "increment" section is the most crucial part for  separation, and I didn't make it correct until today.

        while (1)
        {
            int t = 0;
            for (j = 0; j < barsel[0]; j++)
            {
                bardesel[t++] = j;
            }
            for (i = 1; i < k; ++i)
            {
                for (j = barsel[i-1] + 1; j < barsel[i]; j++)
                {
                    bardesel[t++] = j;
                }
            }
            for (j = barsel[k-1] + 1; j < k2; j++)
            {
                bardesel[t++] = j;
            }

            Permute(barsel, bardesel);

            // increment
            for (j = k - 1; j >= 0; j--)
            {
                int nbsj = barsel[j] + 1;
                while (nbsj < k2 && barvec[nbsj] == barvec[barsel[j]])
                {
                    nbsj++;
                }
                setcode -= barcode[barsel[j]];
                if (k2 - nbsj < k - j)
                {
                    continue;
                }

                int oldsetcode = setcode;
                setcode += barcode[nbsj];
                if (setcode > halfcode || (setcode * 2 == totalcode) && barsel[0] != 0)
                {
                    setcode = oldsetcode;
                    continue;
                }

                barsel[j] = nbsj;

                // flush
                int oldj = j;
                j++;
                for ( ; j < k; j++)
                {
                    barsel[j] = barsel[j-1] + 1;
                    setcode += barcode[barsel[j]];
                    if (setcode > halfcode)
                    {
                        break;
                    }
                }
                if (setcode > halfcode || (setcode * 2 == totalcode) && barsel[0] != 0)
                {
                    setcode = oldsetcode;
                    j = oldj;
                    continue;
                }
                break;
            }
            if (j < 0)
            {
                break;
            }
        }
    }


public:
    int countSolutions(vector <string> bars)
    {
        // clear
        barvec.clear();

        // Parse Bars
        k2 = bars.size();
        k = k2 / 2;
        int total = 0;

        for (int i = 0; i < k2; ++i)
        {
            string &barstr = bars[i];
            Bar        bar;
            bar.val.resize(k);

            for (int j = 0; j < k; j++)
            {
                bar.val[j] = (barstr[j] == 'S')? 0 : 1;
                total += bar.val[j];
            }

            bar.Normalize();

            BarVec::iterator itr = barvec.begin();
            for ( ; itr != barvec.end() && *itr < bar ; ++itr)
            {
            }

            barvec.insert(itr, bar);
        }

        if (total != k * k)
        {
            return 0;
        }

        count=0;

        // separate
        Separate();

        return count;
    }
};



#include <cstdio>

void Fuel (int test_idx, vector <string> &bars, int &res)
{
    char *k_test0[] = {"SD", "SD", "SD", "SD"};
    char *k_test1[] = {"SDS", "SDS", "SDS", "DDD","SSS","DDD"};
    char *k_test2[] = {"SDD", "SSS", "SDS", "DDD", "SDD", "DSS"};
    char *k_test3[] = {"SDDS", "SDDS", "SDDS", "SDDS", "SDDS", "SDDS", "SDDS", "SDDS"};
    char *k_test4[] = {"DSDD", "DDSD", "SDDD", "SSSS", "DSSD", "DSSS", "SSDD", "SDSD"};
    char *k_test5[] = {"SSSS","SSSS","SSSS","SSSS","DDDD","DDDD","DDDD","DDDD"};

    int k_res[] = {1, 2, 9, 0, 80, 1};
    res = k_res[test_idx];
   
    #define SIZE(n)    (sizeof(k_test##n)/sizeof(char*))
    char **k_tests[] = { k_test0, k_test1, k_test2, k_test3, k_test4, k_test5 };
    int k_size[] = {SIZE(0), SIZE(1), SIZE(2), SIZE(3), SIZE(4), SIZE(5)};
   
    for (int i = 0; i < k_size[test_idx]; i++)
    {
        string str = k_tests[test_idx][i];
        bars.push_back(str);
    }
}


int main (void)
{
    NotchedWoodBarsPuzzle    puzzle;

    for (int test_idx = 0; test_idx < 6; test_idx++)
    {
        vector<string> bars;
        int stdres;
        Fuel(test_idx, bars, stdres);
        int res = puzzle.countSolutions(bars);
        printf("test[%d].res = %d ...", test_idx, res);
        if (res != stdres)
        {
            printf("error(std = %d)/n", stdres);
        }
        else
        {
            printf("ok/n", stdres);
        }
    }

    return 0;
}

 
posted @ 2008-04-08 20:10  quanben  阅读(167)  评论(0编辑  收藏  举报