TopCoder Practices: PhoneNetwork

来源:互联网 发布:拙心网络企业电话 编辑:程序博客网 时间:2024/06/07 23:49
My 300-point answer to the 1000-point problem (TCO06 Championship Round). Incomplete solution, for only as much as 31-fold edge is allowed, which is below 50, the constraint of line number. About 1 week devising, coding and debugging.

The following is the code.

#include <iostream>
#include <cassert>
#include <conio.h>
#include <cstdio>
#include <vector>
#include <string>
#include <stack>

using namespace std;

class PhoneNetwork
{
public:
    typedef vector<int>     IntVec;
    typedef vector<IntVec>  IntGrid;
    typedef vector<IntGrid> IntLayers;

protected:
    struct SubGraph
    {
        IntGrid     srcg;

        IntGrid     grid;
        IntVec      head;
        IntGrid     prev;
        IntGrid     next;
        IntVec      tail;

        // values
        IntLayers   qmat, cmat;
        int            quality, cost;

        int         n;

        int         q_head;
        int         q_tail;
        IntVec      q_prev;
        IntVec      q_next;
        IntVec      q_ref;
        int         q_depth;

        stack<int>  stk_used;

        int         free_head;
        vector<int> free_prev;
        vector<int> free_next;

        enum
        {
            Init0,
            Init1,
            Inc
        }   state;

        void Init ()
        {
            int i, j;

            n = srcg.size();

            quality = 0;
            cost = 0;

            free_next.resize(n);
            free_prev.resize(n);

            head.resize(n);
            tail.resize(n);
            SetGridSizeNClear(grid, n);
            SetGridSizeNClear(prev, n);
            SetGridSizeNClear(next, n);

            q_next.resize(n);
            q_prev.resize(n);
            q_ref.resize(n, 0);

            // free list
            free_head = 0;
            for (i = 0; i < n; i++)
            {
                free_next[i] = i + 1;
                free_prev[i] = i - 1;
            }

            // grid
            for (i = 0; i < n; i++)
            {
                int p = -1;
                head[i] = n;
                for (j = 0; j < n; j++)
                {
                    grid[i][j] = 0;
                    if (srcg[i][j])
                    {
                        prev[i][j] = p;
                        if (p >= 0) { next[i][p] = j; }
                        else { head[i] = j; }
                        p = j;
                    }
                    else
                    {
                        prev[i][j] = -2;
                        next[i][j] = -2;
                    }
                }
                if (p >= 0)
                {
                    next[i][p] = n;
                }
                tail[i] = p;
            }

            // queue
            q_head = n;
            q_tail = -1;
            q_depth = 0;
            for (i = 0; i < n; i++)
            {
                q_prev[i] = -2;
                q_next[i] = -2;
                q_ref[i] = 0;
            }

            while (!stk_used.empty())
            {
                stk_used.pop();
            }
        }

        void QPush (int i)
        {
            if (q_depth == 0)
            {
                q_head = q_tail = i;
                q_next[i] = n;
                q_prev[i] = -1;
                q_depth = 1;
            }
            else
            {
                int j;
                for (j = q_head; j < n; j = q_next[j])
                {
                    if (j == i) return;
                    if (j > i) break;
                }

                if (j < n) { q_prev[i] = q_prev[j]; q_prev[j] = i; q_next[i] = j; }
                else { q_prev[i] = q_tail; q_tail = i; q_next[i] = n; }
                j = q_prev[i];
                if (j >= 0) { q_next[j] = i; }
                else { q_head = i; }
                q_depth++;
            }
        }

        void QPop (int i)
        {
            if (q_next[i] == -2)
            {
                return;
            }
            if (q_prev[i] >= 0) { q_next[q_prev[i]] = q_next[i]; }
            else { q_head = q_next[i]; }
            if (q_next[i] < n) { q_prev[q_next[i]] = q_prev[i]; }
            else { q_tail = q_prev[i]; }
            q_next[i] = -2;
            q_prev[i] = -2;
            q_depth--;
        }

        bool QGet (int &i)
        {
            if (q_depth == 0) return false;
            i = q_head;
            q_head = q_next[q_head];
            q_next[i] = q_prev[i] = -2;
            if (q_head < n)
            {
                q_prev[q_head] = -1;
            }
            if (q_head > q_tail)
            {
                q_tail = q_head;
            }
            q_depth--;
            if (q_depth == 0)
            {
                q_head = n; q_tail = -1;
            }
            return true;
        }

        void QSet (int i, int d)
        {
            q_ref[i] += d;
            if (q_ref[i] < 0)
            {
                assert(0);
            }
            if (q_ref[i] == 0)  // never < 0
            {
                QPop(i);
            }
            else
            {
                QPush(i);
            }
        }

        int QSize ()
        {
            return q_depth;
        }

        void SPush (int i)
        {
            stk_used.push(i);

            if (free_prev[i] >= 0)
            {
                free_next[free_prev[i]] = free_next[i];
            }
            else
            {
                free_head = free_next[i];
            }
            if (free_next[i] < n)
            {
                free_prev[free_next[i]] = free_prev[i];
            }

            // clear i
            for (int j = free_head; j < n; j = free_next[j])
            {
                grid[j][i] = 0;

                if (prev[j][i] != -2)
                {
                    if (prev[j][i] >= 0) { next[j][prev[j][i]] = next[j][i]; }
                    else { head[j] = next[j][i]; }
                    if (next[j][i] < n) { prev[j][next[j][i]] = prev[j][i]; }
                    else { tail[j] = prev[j][i]; }
                }
            }
        }

        void STop (int &i)
        {
            i = stk_used.top();
        }

        void SPop ()
        {
            int i = stk_used.top();
            stk_used.pop();

            // restore i
            for (int j = free_head; j < n; j = free_next[j])
            {
                if (prev[j][i] != -2)
                {
                    if (prev[j][i] >= 0) { next[j][prev[j][i]] = i; }
                    else { head[j] = i; }
                    if (next[j][i] < n) { prev[j][next[j][i]] = i; }
                    else { tail[j] = i; }
                }
            }

            if (free_prev[i] >= 0) { free_next[free_prev[i]] = i; }
            else { free_head = i; }
            if (free_next[i] < n) { free_prev[free_next[i]] = i; }
        }

        int SSize ()
        {
            return stk_used.size();
        }

        bool First ()
        {
            SPush(0);
            state = Init1;
            return Try();
        }

        bool Next ()
        {
            state = Inc;
            return Try();
        }

        void SetQC (int i, int j, int add, int minus)
        {
            int h = cmat[i][j].size();
            int m = 1;
            assert(h < 32);
            for (int k = 0; k < h; k++, m<<=1)
            {
                if ((add & m) & ~(minus & m))
                {
                    cost += cmat[i][j][k];
                    quality += qmat[i][j][k];
                }
                else if ((minus & m) & ~(add & m))
                {
                    cost -= cmat[i][j][k];
                    quality -= qmat[i][j][k];
                }
            }
        }

        bool Try ()   // this function generates next connected subtree
        {
            // prev[0] points to the first one
            int i, j;
            bool to_push = false;

            STop(i);
            while (1)
            {
                if (state == Inc)
                {   // inc by one, from stack pop
                    // always something to push

                    for (j = head[i]; j < n ; )
                    {
                        int oldv = grid[i][j];
                        grid[i][j]++;
                        if (grid[i][j] > srcg[i][j])
                        {
                            int newv = grid[i][j] = 0;

                            SetQC(i, j, 0, oldv);

                            QSet(j, newv - oldv);
                            j = next[i][j];
                        }
                        else
                        {
                            int newv = grid[i][j];
                           
                            SetQC(i, j, newv, oldv);

                            QSet(j, newv - oldv);
                            break;
                        }
                    }
                    if (j == n)
                    {
                        // i
                        QPush(i);   // ref to i must be positive

                        // all branches have already been cleared

                        SPop();
                        if (SSize() == 0)
                        {
                            return false;
                        }

                        STop(i);
                        to_push = false;
                        state = Inc;
                        continue;
                    }
                }
                else
                {   // reset to zero, from queue pop
                    j = head[i];
                    if ( j < n )
                    {
                        if (state == Init1)
                        {
                            SetQC(i, j, 1, 0);

                            grid[i][j] = 1;
                            QSet(j, 1);
                        }
                        else    // state == Init0
                        {
                            grid[i][j] = 0;
                        }
                        j = next[i][j];
                    }

                    for ( ; j < n ; j = next[i][j])
                    {
                        grid[i][j] = 0;
                    }

                    if (QSize() == 0)
                    {
                        to_push = false;
                    }
                }
                if (to_push)
                {
                    SPush(i);
                }

                if (SSize() == n - 1)
                {
                    return true;
                }
                if (!QGet(i))
                {
                    if (SSize() <= 0)
                    {
                        return false;
                    }

                    STop(i);
                    state = Inc;
                }
                else
                {
                    // no hope if reset
                    if (QSize() == 0)
                    {
                        state = Init1;
                    }
                    else
                    {
                        state = Init0;
                    }
                    to_push = true;
                }
            }
        }
    };

public:
    static void SetGridSizeNClear (IntGrid &g, int n)
    {
        g.resize(n);
        for (int i = 0; i < n; i++)
        {
            g[i].resize(n, 0);
        }
    }
    static void SetLayersSize (IntLayers &g, int n)
    {
        g.resize(n);
        for (int i = 0; i < n; i++)
        {
            g[i].resize(n);
            for (int j = 0; j < n; j++)
            {
                g[i][j].resize(0);
            }
        }
    }

    double bestQuality (int numPoints, vector <string> cables)
    {
        int numCables = cables.size();
       
        SubGraph    subg;

        double  cur;
        double  m = 0.0;

        SetGridSizeNClear(subg.srcg, numPoints);
        SetLayersSize(subg.qmat, numPoints);
        SetLayersSize(subg.cmat, numPoints);

        for (int cableIdx = 0; cableIdx < numCables; cableIdx++)
        {
            string &s = cables[cableIdx];

            int i, j;
            int q, c;
           
            sscanf(s.c_str(), "%d %d %d %d", &i, &j, &q, &c);
            i--, j--;
            subg.cmat[i][j].push_back(c);
            subg.cmat[j][i].push_back(c);
            subg.qmat[i][j].push_back(q);
            subg.qmat[j][i].push_back(q);
            int h = subg.qmat[j][i].size();
            subg.srcg[i][j] =
            subg.srcg[j][i] = (1<<h) - 1;
        }

        subg.Init();
        if (subg.First())
        { 
            cur = (double)subg.quality / (double)subg.cost;
            if (m < cur) { m = cur; }

            while (subg.Next())
            {
                cur = (double)subg.quality / (double)subg.cost;
                if (m < cur) { m = cur; }
            }
            return m;
        }
        else
        {
            return -1.0;
        }
    }
};


static char *k_str0[] = {"1 2 6 5","2 3 3 4","3 4 5 2","4 1 3 3"};
static char *k_str1[] = {"1 2 6 5","2 3 3 4","3 4 5 2","4 1 3 3"};
static char *k_str2[] = {"1 2 1 10","2 3 3 3","2 4 3 2","3 4 3 1","3 4 2 1"};

static int k_numpts[] = {4,5,4};
static double k_result[] = {1.4, -1.0, 0.7058823529411765};
static char **k_strs[] = { k_str0, k_str1, k_str2 };
#define TOTALTESTS    (sizeof(k_numpts)/sizeof(int))
#define STRNUM(ss)    sizeof(k_str##ss)/sizeof(char *)
static int k_strnum[] = {STRNUM(0), STRNUM(1), STRNUM(2)};

bool Fuel (int test_idx, int &numPoints, vector<string> &cables, double &res)
{
    if (test_idx > TOTALTESTS)
    {
        return false;
    }
    cables.clear();
    for (int i = 0; i < k_strnum[test_idx]; i++)
    {
        cables.push_back(k_strs[test_idx][i]);
    }
    numPoints = k_numpts[test_idx];
    res = k_result[test_idx];
    return true;
}

int main (void)
{
    for (int tidx = 0; tidx < TOTALTESTS; tidx++)
    {
        PhoneNetwork pn;
        int numPoints;
        vector<string>  cables;
        double res;
        Fuel(tidx, numPoints, cables, res);
        printf("hey/n");
        double m = pn.bestQuality(numPoints, cables);
        cout << "test " << tidx << ": outp=" << m << " std=" << res << " " << endl;
    }

    return 0;
}