-
Notifications
You must be signed in to change notification settings - Fork 5
algorithm adventures in moving part iv
Jongbin Oh edited this page Jun 8, 2013
·
1 revision
- 최대 10000Km 거리의 목표지 까지 최소의 기름값을 쓰면서 도착하는 방법은?
- 최대 10000 + 1 + 100 Km 를 인덱스로 DP 테이블을 만듬.
- 각 위치에서의 최소 기름값을 구해서 DP 테이블 완성
- DP 테이블을 돌면서 기름값을 누적 시켜나가 답을 구한다.
- Wrong 한번, Presentation Error 한번, Solved.. 오 럭키!
- 입출력이 까탈스럽네요;
// "Adventures in Moving - Part IV" Solution By Outbreak
#include <iostream>
#include <vector>
using namespace std;
//#define _TDD
//--------------------------------------------------------------------
namespace Solver
{
static const int IMPOSSIBLE_PRICE = 10000;
static const int MAX_DISTANCE = 10001;
static const int MAX_GAS_SIZE = 200;
static const int DEFAULT_GAS_SIZE = 100;
static vector<int> VPrice(MAX_DISTANCE+DEFAULT_GAS_SIZE,IMPOSSIBLE_PRICE);
// 1. > DP 테이블 초기화
void MakePriceTable()
{
int i;
for( i=0; i<MAX_DISTANCE+DEFAULT_GAS_SIZE; i++ )
{
VPrice[i] = IMPOSSIBLE_PRICE;
}
for( i=0; i<=DEFAULT_GAS_SIZE; i++ )
{
VPrice[i] = 0;
}
}
// 2. > DP 테이블 만들기 - 각 주유소를 중심으로!
void InsertPrice( int dist, int price )
{
// 현재 위치에서 제일 싼 가격
for(int i=1;i<=MAX_GAS_SIZE;i++)
{
if(VPrice[ dist+i ] > price)
{
VPrice[ dist+i ] = price;
}
}
}
// 3. > 최소 비용 구하기
int CalcMinimumPrice(int distance)
{
int price = 0;
// 각 위치에서의 주유 가격을 더해 나가면서 총 비용을 산출한다.
// 반납 시 기름통의 반이 채워져 있어야 하므로 그 만큼을 더 간다고 생각한다.
for(int i=1; i<=distance+DEFAULT_GAS_SIZE; i++)
{
if (VPrice[i] == IMPOSSIBLE_PRICE)
{
return -1;
}
price += VPrice[i];
}
return price;
}
}
//--------------------------------------------------------------------
namespace Runner
{
void Execute(istream& in, ostream& out)
{
int sample = 0;
in >> sample;
while( sample-- )
{
int distance = 0, dist = 0, price = 0;
in >> distance;
Solver::MakePriceTable();
while(true)
{
in.get();
// 개행이 한개 더오면 다음 샘플 처리
if( in.peek() == '\n')
{
break;
}
in >> dist >> price;
if( in.fail() )
break;
Solver::InsertPrice(dist, price);
}
int result = Solver::CalcMinimumPrice(distance);
if( result == -1 )
{
out << "Impossible" << endl;
}
else
{
out << result << endl;
}
if( sample > 0 )
{
out << endl;
}
}
}
}
//--------------------------------------------------------------------
#ifdef _TDD
#include "unittest++.h"
struct TEST_BASE
{
stringstream input;
stringstream output;
};
TEST_FIXTURE(TEST_BASE, PresentationTest)
{
input <<
"2\n"
"\n"
"500\n"
"100 999\n"
"150 888\n"
"200 777\n"
"300 999\n"
"400 1009\n"
"450 1019\n"
"500 1399\n";
input << "\n";
input <<
"500\n"
"100 999\n"
"150 888\n"
"200 777\n"
"300 999\n"
"400 1009\n"
"450 1019\n"
"500 1399\n";
Runner::Execute(input, output);
CHECK_EQUAL( "450550\n\n450550\n", output.str());
}
#endif
//--------------------------------------------------------------------
int main()
{
#ifdef _TDD
UnitTest::RunAllTests();
#else
Runner::Execute(cin, cout);
#endif // _TDD
return 0;
}
-
주유소 들릴 때마다 항상 탱크를 꽉 채워야 한다는 가정이 있다면 이것도 답이 될 수 있겠지만, 역시 무엇을 DP table 로 만들 것인가를 잘 못 생각했네요. 쩝...
-
새로 푼 문제는 준석씨랑 똑같이 풀었기 때문에 따로 올리지 않습니다. :)
-
그러니까 아래 코드는 잘 못 푼 거라는 거.. T_T
/* @JUDGE_ID:parkpd 110401 Cpp "test" */ /* @BEGIN_OF_SOURCE_CODE */ #include <iostream> #include <vector> #include <set> #include <deque> #include <list> #include <stack> #include <string> #include <algorithm> #include <map> #include <limits> #include <assert.h> #include <iomanip> #include <math.h> #define _UNIT_TEST #ifdef _UNIT_TEST #include <Windows.h> #endif using namespace std; namespace ATUtil { bool IsInRange(int value, int from, int to) { return (from <= value) && (value <= to); } int ConvertToIndex(char c) { if ('a' <= c && c <= 'z') { return c - 'a'; } else { return -1; } } char ConvertToChar(int i) { return (char)i + 'a'; } #ifdef _UNIT_TEST class CStopWatch { public: CStopWatch() { m_StartTick = GetTickCount(); // gcc 에서 안 될 수 있으니까 } ~CStopWatch() { cout << "Time passed : " << GetTickCount() - m_StartTick << " milisec.\n"; } int m_StartTick; }; #endif typedef map<int, int> IntDB; typedef vector<int> Ints; typedef list<int> IntList; }; using namespace ATUtil; #ifdef _UNIT_TEST #include "../UnitTest++/src/UnitTest++.h" #ifdef max #undef max #endif #ifdef min #undef min #endif int main() { UnitTest::RunAllTests(); char temp; cin >> temp; return 0; } #endif // code implement namespace ATCode { ////////////////////////////////////////////////////////////////////////// // CStation class CStation { public: CStation(int d, int c) : m_Dist(d), m_Cost(c), m_TotalCost(0) {} int m_Dist; int m_Cost; int m_TotalCost; }; ////////////////////////////////////////////////////////////////////////// // CStationNavi class CStationNavi { public: enum {MAX_STATIONS = 9}; // 100 이상의 연료를 남기기 위해, 아예 거리를 늘려준다. CStationNavi(int dist) : m_Dist(dist + 100) { // 출발지도 일종의 주유소로 생각하자. // 미리 가지고 있는 가스 100 만큼을 뺀 거리에서 가스 200 을 채웠다고 생각하고 시작한다. Input(-100, 0); } void Input(int d, int c) { m_Stations.push_back(CStation(d, c)); } template<typename InputIterator> void Inputs(InputIterator f, InputIterator t) { for (InputIterator i = f; i < t; i += 2) { Input(*i, *(i+ 1)); } } int CalcDirectCost(int from, int to) { if (-1 == m_CostTable[from][to]) { const int distBetweenStation = m_Stations[to].m_Dist - m_Stations[from].m_Dist; if (200 < distBetweenStation) { m_CostTable[from][to] = numeric_limits<int>::max(); // 갈 수 없음. } else { m_CostTable[from][to] = m_Stations[from].m_Cost * (distBetweenStation); } } return m_CostTable[from][to]; } int CalcCost(int from, int to) { // TODO : 가스가 부족하면 무한대를 리턴해야 한다. 어떻게? // Cs-t = min(Cs-t, min(k=s-t)(Cs-k, Ck-t)) if ((from == to) || (from + 1 == to)) { return CalcDirectCost(from, to); } else { // Cs-t = min(Cs-t, min(k=s-t)(Cs-k, Ck-t)) int minCost = numeric_limits<int>::max(); for (int k = from + 1; k < to; ++k) { int cost = CalcCost(from, k) + CalcCost(k, to); if (cost < minCost) { minCost = cost; } } m_CostTable[from][to] = min(CalcDirectCost(from, to), minCost); return m_CostTable[from][to]; } } int Calc() { Input(m_Dist, 0); // 목적지도 일종의 주유소로 생각하자. // Cs-t = min(Cs-t, min(k=s-t)(Cs-k, Ck-t)) // case 1. // C0-2 = min(C0-2, C0-1 + C1-2) for (int r = 0; r < MAX_STATIONS; ++r) { for (int c = 0; c < MAX_STATIONS; ++c) { if (r == c) { m_CostTable[r][c] = 0; } else { m_CostTable[r][c] = -1; } } } const int numStations = (int)m_Stations.size(); int calcCost = 0; for (int diagonal = 1; diagonal <= numStations; ++diagonal) { for (int r = 0; r < numStations - diagonal; ++r) { int c = r + diagonal; //cout << r << c << "\n"; //m_CostTable[r][c] = //min(m_CostTable[r][c], //min(k)(m_CostTable[r][k] + m_CostTable[k][c]); calcCost = CalcCost(r, c); m_CostTable[r][c] = calcCost; } } return m_CostTable[0][numStations - 1]; } int m_Dist; vector<CStation> m_Stations; int m_CostTable[MAX_STATIONS][MAX_STATIONS]; }; /////////////////////////////////////////////////////////////// // CConsole class CConsole { public: static void ConsoleTest(istream& input, ostream& output); }; void CConsole::ConsoleTest(istream& input, ostream& output) { int testCount = 0; input >> testCount; for (int i = 0; i < testCount; ++i) { if (1 <= i) { output << "\n"; } int dist; input >> dist; CStationNavi navi(dist); int pos, price; while (input >> pos >> price) { navi.Input(pos, price); } output << navi.Calc() << "\n"; } }; } using namespace ATCode; #ifndef _UNIT_TEST int main() { CConsole::ConsoleTest(cin, cout); return 0; } #else // tests struct FixtureBase { FixtureBase() { } stringstream input; stringstream output; }; TEST_FIXTURE(FixtureBase, Case2) { int stations[] = {100, 999, 200, 1000}; CStationNavi n(300); n.Inputs(&stations[0], &stations[sizeof(stations) / sizeof(int)]); CHECK_EQUAL(0, n.Calc()); } TEST_FIXTURE(FixtureBase, Case1) { int stations[] = {50, 999}; CStationNavi n(100); n.Inputs(&stations[0], &stations[sizeof(stations) / sizeof(int)]); CHECK_EQUAL(0, n.Calc()); } TEST_FIXTURE(FixtureBase, ConsoleTest) { input << "1\n" "\n" "500\n" "100 999\n" "150 888\n" "200 777\n" "300 999\n" "400 1009\n" "450 1019\n" "500 1399\n"; CConsole::ConsoleTest(input, output); CHECK_EQUAL( "450550\n", output.str()); } #endif /* @END_OF_SOURCE_CODE */