TopCoder Practices: PhoneNetwork
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;
}
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;
}
enjoy every minute of an appless, googless and oracless life