Skip to content

Instantly share code, notes, and snippets.

@mizuhara
Created September 7, 2016 13:30
Show Gist options
  • Save mizuhara/19d2de979b0303534bc8246ecbc7b30d to your computer and use it in GitHub Desktop.
Save mizuhara/19d2de979b0303534bc8246ecbc7b30d to your computer and use it in GitHub Desktop.
#include <set>
#include <regex>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
const std::size_t base = 16;
std::vector<std::string> split(const std::string & src, const std::string & separator)
{
std::vector<std::string> ret;
const std::regex reg = separator.empty() ? std::regex("(.{1})") : std::regex(separator);
const auto flag = separator.empty() ? 1 : -1;
std::copy(std::sregex_token_iterator(src.begin(), src.end(), reg, flag), std::sregex_token_iterator(), std::back_inserter(ret));
return ret;
}
std::queue<std::size_t> listupUnknownBits(const std::string & lighting, const std::string & not_lighting)
{
std::queue<std::size_t> unknown;
const auto known = stoi(lighting, nullptr, base) | stoi(not_lighting, nullptr, base);
for(std::size_t i = 0; i < 7; ++i) {
if(!(known & (1 << i))) {
unknown.push(i);
}
}
return unknown;
}
std::set<int> dropNan(const std::set<int> & numbers)
{
std::set<int> ret;
static const std::vector<std::string> hex = { "3f", "06", "5b", "4f", "66", "6d", "7d", "27", "7f", "6f" };
for(auto && number : numbers) {
for(std::size_t i = 0; i < hex.size(); ++i) {
if(number == stoi(hex[i], nullptr, base)) {
ret.insert(i);
}
}
}
return ret;
}
std::set<int> listupConcievableNumbers(std::queue<std::size_t> & unknown, const std::set<int> & s)
{
if(unknown.empty()) {
return dropNan(s);
}
std::queue<std::size_t> q = unknown; q.pop();
std::set<int> updatedS = s;
while(!unknown.empty()) {
const auto unknownBit = unknown.front(); unknown.pop();
for(auto && n : s) {
updatedS.insert(n | (1 << unknownBit));
}
}
return listupConcievableNumbers(q, updatedS);
}
enum class Value
{
Zero = 0,
One,
Two,
Three,
Four,
Five,
Six,
Seven,
Eight,
Nine,
Unknown,
};
class Segment
{
public:
Segment(const std::string & lighting, const std::string & notLighting)
:lighting_(lighting), notLighting_(notLighting)
{}
Value minValue() const
{
auto unknown = listupUnknownBits(lighting_, notLighting_);
std::set<int> s; s.insert(stoi(lighting_, nullptr, base));
const auto numbers = listupConcievableNumbers(unknown, s);
if(numbers.empty()) {
return Value::Unknown;
}
return static_cast<Value>(*std::min_element(std::begin(numbers), std::end(numbers)));
}
Value minValueHead() const
{
auto unknown = listupUnknownBits(lighting_, notLighting_);
std::set<int> s; s.insert(stoi(lighting_, nullptr, base));
const auto numbers = listupConcievableNumbers(unknown, s);
if(numbers.empty()) {
return Value::Unknown;
}
const auto it = numbers.upper_bound(0);
return (it == numbers.end()) ? Value::Unknown : static_cast<Value>(*it);
}
Value maxValue() const
{
auto unknown = listupUnknownBits(lighting_, notLighting_);
std::set<int> s; s.insert(stoi(lighting_, nullptr, base));
const auto numbers = listupConcievableNumbers(unknown, s);
if(numbers.empty()) {
return Value::Unknown;
}
return static_cast<Value>(*std::max_element(std::begin(numbers), std::end(numbers)));
}
bool isLighting() const { return lighting_ != "00"; }
private:
const std::string lighting_;
const std::string notLighting_;
};
std::vector<Segment> makeSegments(const std::string & src)
{
const auto lightingAndNotLighting = split(src, ",");
const auto lighting = split(lightingAndNotLighting[0], ":");
const auto notLighting = split(lightingAndNotLighting[1], ":");
std::vector<Segment> ret;
for(std::size_t i = 0; i < lighting.size(); ++i) {
ret.emplace_back(lighting[i], notLighting[i]);
}
return ret;
}
std::string calculateMaxValue(const std::vector<Segment> & segments)
{
std::string max;
for(auto && segment : segments) {
const auto maxValue = segment.maxValue();
if(maxValue == Value::Unknown) {
max = "";
if(segment.isLighting()) {
return max;
}
} else {
max += std::to_string(static_cast<int>(maxValue));
}
}
return max;
}
std::string calculateMinValue(const std::vector<Segment> & segments)
{
std::string min;
auto segmentSize = segments.size();
for(auto && segment :segments) {
--segmentSize;
const auto minValue = segment.minValue();
// Head以降の数値を算出する.
if(!min.empty()) {
min += (minValue == Value::Unknown) ? "" : std::to_string(static_cast<int>(minValue));
continue;
}
// Headの数値を算出する.
const auto minValueHead = segment.minValueHead();
if(segment.isLighting() && segmentSize != 0) {
if(minValueHead == Value::Unknown) {
break;
}
}
if(segment.isLighting() || segmentSize == 0) {
if(minValueHead == Value::Unknown) {
min += std::to_string(static_cast<int>(minValue));
} else if(minValueHead == Value::Zero) {
min += std::to_string(static_cast<int>(minValueHead));
} else {
min += (segmentSize == 0) ? std::to_string(static_cast<int>(minValue)) : std::to_string(static_cast<int>(minValueHead));
}
}
}
return min;
}
std::string solve(const std::string & src)
{
const auto segments = makeSegments(src);
const auto minValue = calculateMinValue(segments);
const auto maxValue = calculateMaxValue(segments);
return (minValue.empty() || maxValue.empty()) ? "-" : minValue + "," + maxValue;
}
void test(const std::string & src, const std::string & expected)
{
static int no = 0;
const auto actual = solve(src);
std::cout << no++ << ":" << (actual == expected ? "ok" : "***NG***") << std::endl;
}
int main()
{
/*0*/ test( "06:4b:46:64:6d,79:20:10:10:02", "12345,13996" );
/*1*/ test( "41:00,3e:01", "-" );
/*2*/ test( "00:00,79:79", "1,11" );
/*3*/ test( "02:4b:46:64,20:20:10:10", "1234,3399" );
/*4*/ test( "06:2f:3f:27,40:00:00:40", "1000,7987" );
/*5*/ test( "00:3d:2d:26,00:00:00:00", "600,9899" );
/*6*/ test( "40:20:10,00:00:00", "200,998" );
/*7*/ test( "00:00:00,40:20:10", "1,739" );
/*8*/ test( "08:04:02:01,00:00:00:00", "2000,9999" );
/*9*/ test( "00:00:00:00,08:04:02:01", "1,7264" );
/*10*/ test( "08:04:02:01,01:02:04:08", "-" );
/*11*/ test( "04:02:01,02:04:08", "527,627" );
/*12*/ test( "04:02:01:40:10,02:04:08:10:20", "52732,62792" );
/*13*/ test( "00:30:07,00:01:10", "-" );
/*14*/ test( "37,00", "0,8" );
/*15*/ test( "3f,40", "0,0" );
/*16*/ test( "3f:3f,40:40", "-" );
/*17*/ test( "00:3f,40:40", "0,70" );
/*18*/ test( "00:3f,38:00", "0,18" );
/*19*/ test( "18,07", "-" );
/*20*/ test( "08,10", "3,9" );
/*21*/ test( "42,11", "4,4" );
/*22*/ test( "18,05", "-" );
/*23*/ test( "10:00,0b:33", "-" );
/*24*/ test( "14:02,00:30", "61,83" );
/*25*/ test( "00:1a,3d:04", "2,2" );
/*26*/ test( "00:28,38:40", "0,10" );
/*27*/ test( "20:08:12,4f:37:24", "-" );
/*28*/ test( "02:4c:18,00:00:04", "132,992" );
/*29*/ test( "4a:7a:02,10:00:30", "381,983" );
/*30*/ test( "00:00:06,0b:11:08", "1,47" );
/*31*/ test( "04:20:2c:14,39:08:50:09", "-" );
/*32*/ test( "02:06:02:02,00:31:18:11", "1111,9174" );
/*33*/ test( "00:04:48:50,03:02:20:02", "526,636" );
/*34*/ test( "00:58:42:40,00:20:08:12", "245,9245" );
/*35*/ test( "08:08:60:00:32,76:67:02:16:04", "-" );
/*36*/ test( "00:00:00:08:02,06:1a:3b:20:11", "21,34" );
/*37*/ test( "08:58:12:06:12,10:20:20:00:04", "32202,92292" );
/*38*/ test( "00:10:74:4e:10,10:04:02:00:24", "2632,92692" );
/*39*/ test( "44:76:0a:00:0c:44,39:08:11:09:02:11", "-" );
/*40*/ test( "00:00:44:0a:04:00,79:06:02:04:79:28", "5211,6211" );
/*41*/ test( "30:02:02:2c:0e:02,00:08:04:02:20:01", "612531,872634" );
/*42*/ test( "00:00:04:10:00:60,25:19:01:02:24:00", "1624,44629" );
/*43*/ test( "04:18:54:38:00:14:70,10:65:09:01:6c:00:0d", "-" );
/*44*/ test( "18:04:26:20:04:24:1a,02:21:50:48:02:08:00", "6177540,6177678" );
/*45*/ test( "00:08:34:00:00:64:06,18:24:02:00:61:08:61", "260141,7269141" );
/*46*/ test( "00:02:0a:04:4a:00:20,18:21:24:02:04:60:19", "125214,7126214" );
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment