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;
}