출처: https://train.usaco.org/usacogate


문제 설명

출처 : IOI'96 - Problem 5

...

The first K characters of S are the prefix of S with length K. 

Write a program which accepts as input a set of primitives and a sequence of constituents and then computes the length of the longest prefix that can be composed from primitives. 

입력

First, the input file contains the list (length 1..200) of primitives (length 1..10) expressed as a series of space-separated strings of uppercase characters on one or more lines.

The list of primitives is terminated by a line that contains nothing more than a period (`.').

No primitive appears twice in the list.

 

Then, the input file contains a sequence S (length 1..200,000) expressed as one or more lines, none of which exceeds 76 letters in length.

 

The "newlines" (line terminators) are not part of the string S.

출력

A single line containing an integer that is the length of the longest prefix that can be composed from the set P.

입력 예

A AB BA CA BBC
.
ABABACABAABC

출력 예

11


문제 풀이

만들려고 하는 문자열 길이의 앞에서 부터 출발해서, 부분 문자열이 존재하는지 검사한다. 단순 double loop를 적용해도 부분 문자열의 수를 N, 만들려고 하는 문자열의 길이를 M이라고 하면 O(NM) 정도로 해결가능해진다.

프로그램 내용

더보기
... 
	// string target;
	// vector<string> primitives;
    
	dp[0]=1;
	for(int i=0;i< target.size();i++) 
	{
        if(dp[i])
        { 
            for(int j=0;j<primivites.size();j++) 
            {
                if( primivies[j]==target.substr(i,primitives[j].size()) ) 
                {
                    dp[i+primivies[j].size()] = 1;
                }
            }
        }
    }
    ...

 

Chapter 2. Bigger Challenges ( link

'USACO Training' 카테고리의 다른 글

Problem 2.2.3 Preface Numbering  (0) 2021.01.21
Problem 2.1.3 The Castle  (0) 2021.01.07
Problem 2.1.7 Hamming Codes  (0) 2021.01.06
Problem 1.2.5 Greedy Gift Givers - 2  (0) 2021.01.03
Problem 2.1.6 Healthy Holsteins  (0) 2020.02.11

출처: https://train.usaco.org/usacogate


문제 설명

Given N (1 <= N < 3,500), the number of pages in the preface of a book, calculate and print the number of I's, V's, etc. (in order from lowest to highest) required to typeset all the page numbers (in Roman numerals) from 1 through N. 

Do not print letters that do not appear in the page numbers specified.

입력

A single line containing the integer N.

출력

The output lines specify, in ascending order of Roman numeral letters, the letter, a single space,
and the number of times that letter appears on preface page numbers. Stop printing letter totals
after printing the highest value letter used to form preface numbers in the specified set.

입력 예

5

출력 예

I 7
V 2

( I, II, III, IV, V) -> I: 1(1)+2(2)+3(3)+1(4) = 7, V : 1(4) + 1(5) = 2


문제 풀이

1 부터 입력받은 숫자까지 Roman 숫자로 표현할때 각 숫자들이 몇번 나오는지 세는 프로그램을 작성한다.

Roman 숫자표현에서 나오는 문자는 7가지 이다.( I - 1, V - 5, X - 10, L - 50, C - 100 , D - 500, M - 1000) 

이런 7개 문자들이 몇번 나오는지 unordered_map<char, int> 형태로 기록한다.

프로그램 내용

더보기

 

...
	string ones[9] = {"I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"};
    string tens[9] = {"X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"};
    string hundreds[9] = {"C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"};
    string thousands[3] = {"M", "MM", "MMM"};
...
    unordered_map<char, int> m;
    for (int i = 1; i <= N; i++) {
        int num = i;
        
        if (num / 1000 > 0) {
            count(m, thousands[num / 1000 - 1]);
            num %= 1000;
        }
        if (num / 100 > 0) {
            count(m, hundreds[num / 100 - 1]);
            num %= 100;
        }
        if (num / 10 > 0) {
            count(m, tens[num / 10 - 1]);
            num %= 10;
        }
        if (num > 0) {
            count(m, ones[num - 1]);
        }
    }
    if (m.find('I') != m.end()) fout << "I " << m['I'] << endl;
    if (m.find('V') != m.end()) fout << "V " << m['V'] << endl;
    if (m.find('X') != m.end()) fout << "X " << m['X'] << endl;
    if (m.find('L') != m.end()) fout << "L " << m['L'] << endl;
    if (m.find('C') != m.end()) fout << "C " << m['C'] << endl;
    if (m.find('D') != m.end()) fout << "D " << m['D'] << endl;
    if (m.find('M') != m.end()) fout << "M " << m['M'] << endl;
...

 

Chapter 2. Bigger Challenges ( link )

'USACO Training' 카테고리의 다른 글

Section 2.3.1 Prob The Longest Prefix  (0) 2021.04.01
Problem 2.1.3 The Castle  (0) 2021.01.07
Problem 2.1.7 Hamming Codes  (0) 2021.01.06
Problem 1.2.5 Greedy Gift Givers - 2  (0) 2021.01.03
Problem 2.1.6 Healthy Holsteins  (0) 2020.02.11

출처: https://train.usaco.org/usacogate


문제 설명

The castle floorplan is divided into M (wide) by N (1 <=M,N<=50) square modules. Each such module can have between zero and four walls. Castles always have walls on their "outer edges" to keep out the wind and rain.

 

입력

Line 1: Two space-separated integers: M and N
Line 2..: M x N integers, several per line.

출력

Line 1: The number of rooms the castle has.
Line 2: The size of the largest room
Line 3: The size of the largest room creatable by removing one wall
Line 4: The single wall to remove to make the largest room possible

입력 예

7 4
11 6 11 6 3 10 6
7 9 6 13 5 15 5
1 10 12 7 13 7 5
13 11 10 8 10 12 13

출력 예

5
9
16
4 1 E


문제 풀이

IOI'94 - Day 1 의 문제이다. N x M maze에서 연결된 방들을 채워가는 Flood fill 알고리즘을 적용하면, 전체 연결된 방을 알 수 있다. 한방에서 연결된 방을 찾아가는 방법은 DFS가 적용된다.  N x M maze를 다루는 연습이 필요한 문제이다. 벽을 제거하면서 값을 비교할때는 항상 계산이 끝난 다음 원래 값으로 변경시키는 과정을 적용해야 한다.

프로그램 내용

더보기
void fill_cells(int y, int x, int& direction)
{
    if(visited[y][x]) return;
    visited[y][x] = 1;
    before[y][x] = roomNumber;
    direction++;

    if(!(cells[y][x] & 1)) fill_cells(y,x-1, direction); /// Connected Direction: W
    if(!(cells[y][x] & 2)) fill_cells(y-1,x, direction); /// Connected Direction: N
    if(!(cells[y][x] & 4)) fill_cells(y,x+1, direction); /// Connected Direction: E
    if(!(cells[y][x] & 8)) fill_cells(y+1,x, direction); /// Connected Direction: S
};
...

한 방에 도착하면 연결된 벽을 확인하고, 벽으로 막혀 있지 않으면 그 방까지 연결한다.

 /// visit every rooms
    for(int y=1; y <N+1; ++y)
    {
        for(int x=1; x<M+1;++x)
        {
            if(!visited[y][x])
            {
                roomNumber++;
                int tn=0;
                fill_cells(y,x,tn);
                room[roomNumber] = tn;
                if( tn > maxn ) maxn = tn;
            }
        }
    }

    /// remove wall check
    for(int j=1;j<=M;j+=1)
    {
        for(int i=N;i>=1;i-=1)
        {
            if(cells[i][j]&2)if(before[i-1][j] && before[i-1][j]!=before[i][j])
            {
                if( room[before[i-1][j]] + room[before[i][j]] > max2n )
                {
                    max2n = room[before[i-1][j]] + room[before[i][j]];
                    wx = i,wy = j,wd = 'N';
                }
            }

            if(cells[i][j]&4)if(before[i][j+1] && before[i][j+1]!=before[i][j])
            {
                if( room[before[i][j+1]] + room[before[i][j]] > max2n )
                {
                    max2n = room[before[i][j+1]] + room[before[i][j]];
                    wx = i,wy = j,wd = 'E';
                }
            }
        }
    }

전체 방에 대해서 벽을 제거해서 결과값이 최대가 될때마다 제거하는 벽을 기록하는 방법을 적용한다.

 

Chapter 2. Bigger Challenges ( link )

'USACO Training' 카테고리의 다른 글

Section 2.3.1 Prob The Longest Prefix  (0) 2021.04.01
Problem 2.2.3 Preface Numbering  (0) 2021.01.21
Problem 2.1.7 Hamming Codes  (0) 2021.01.06
Problem 1.2.5 Greedy Gift Givers - 2  (0) 2021.01.03
Problem 2.1.6 Healthy Holsteins  (0) 2020.02.11

출처: https://train.usaco.org/usacogate


문제 설명

Given N, B, and D: Find a set of N codewords (1 <= N <= 64), each of length B bits (1 <= B <= 8),
such that each of the codewords is at least Hamming distance of D (1 <= D <= 7) away from each
of the other codewords.

입력

N, B, D on a single line

출력

N codewords, sorted, in decimal, ten per line.

입력 예

16 7 3

출력 예

0 7 25 30 42 45 51 52 75 76
82 85 97 102 120 127


문제 풀이

Hamming Distance 계산하는 방법에 대한 문제이다. 각각의 bit 값을 비교하기 위해서, 2로 계속 나누고 달라질때마다 distance를 증가시키는 방법으로 계산한다. 0 부터 숫자를 키워가면서 distance > D인 경우들을 계속 추가시켜서 기록하고, 출력할때 10개 단위로 출력한다.

프로그램 내용

더보기
int getHammingDistance(int a, int b)
{
    int ret=0;

    while( a> 0 || b>0)
    {
        if( a%2 != b%2)
            ret++;
        a /= 2;
        b /= 2;
    }
    return ret;
};

...

  ans.push_back(0);
    /// check hamming distance > D, put result
    for(int i=0;i < maxB ;i++)
    {
        bool ok= true;

        /// compare hamming distance with last code
        for(int j=0;j!=ans.size();j++)
        {
            /// distance < D
            if( getHammingDistance(i,ans[j]) < D )
            {
                ok = false;
                break;
            }
        }
        /// distance >= D
        if(ok)
        {
            ans.push_back(i);
        }

        /// Max output number
        if(ans.size() >= N)
        {
                break;
        }
    }

 

Chapter 2. Bigger Challenges ( link )

'USACO Training' 카테고리의 다른 글

Problem 2.2.3 Preface Numbering  (0) 2021.01.21
Problem 2.1.3 The Castle  (0) 2021.01.07
Problem 1.2.5 Greedy Gift Givers - 2  (0) 2021.01.03
Problem 2.1.6 Healthy Holsteins  (0) 2020.02.11
USACO Training - Chapter 6. Contest Practice  (0) 2020.01.01

출처: https://cses.fi/problemset/task/1745


문제 설명

You have n coins with certain values. Your task is to find all money sums you can create using these coins.

입력 

The first input line has an integer n: the number of coins.

The next line has n integers x1,x2,,xn : the values of the coins.

출력

First print an integer k: the number of distinct money sums.

After this, print all possible sums in increasing order.

입력 예

4
4 2 5 2

출력 예

9
2 4 5 6 7 8 9 11 13

제약조건

1<= n <=100

1<= x_i <= 1000


문제 풀이

가능한 최대값은 100*1000 (max_n, max_xi) 이다. 가능한 최대값과 같은 크기의 boolean 배열을 만든다. 각 코인마다 값들을 더해가면서 falst->true 로 변경한다. 만들어진 배열에서 true 경우를 세고, dp[u] == true 이면, u가 가능한 값이 된다.

프로그램 내용

더보기
vector<bool> dp(n*1000+1);
...
for (int c : coins) 
{
	for (int i = dp.size() - 1; i > 0; i--) 
	{
            if (dp[i]) 
                dp[i + c] = 1; 
            d[c] = 1; 
	}
}
...

 

Dynamic Programming link )

'CSES' 카테고리의 다른 글

CSES 6. Tree Algorithms  (0) 2021.07.21
CSES 5. Range Queries  (0) 2021.07.21
CSES 3. Rectangle Cutting (1744)  (0) 2020.07.28
CSES 3. Edit Distance (1639)  (0) 2020.03.18
CSES 4. Road Reparation (1675)  (0) 2020.01.20

출처: https://cses.fi/problemset/1744


문제 설명

Given an a×b rectangle, your task is to cut it into squares. On each move you can select a rectangle and cut it into two rectangles in such a way that all side lengths remain integers. What is the minimum possible number of moves?

입력 

The only input line has two integers a and b.

출력

Print one integer: the minimum number of moves.

입력 예

3 5

출력 예

3

제약조건

1 <= a, b <= 500


문제 풀이

모두 정사각형이 되도록 직사각형을 자를때 최소 횟수를 구하는 문제이다. 가로로 자르는 경우와 세로로 자르는 경우로 나눠서 각각 한번 자를때마다, 최소값들을 갱신한다.

프로그램 내용

더보기
...   
for(int i=1; i<=a; ++i) {
	for(int j=1; j<=b; ++j) {
		if(i^j)
			dp[i][j]= INT_MAX;
		for(int k=1; k<i; ++k) // 가로로 자르는 경우
			dp[i][j]=min(dp[i][j], dp[k][j]+dp[i-k][j]+1);
		for(int k=1; k<j; ++k) // 세로로 자르는 경우
			dp[i][j]=min(dp[i][j], dp[i][k]+dp[i][j-k]+1);
	}
}
...

 

Dynamic Programming link )

'CSES' 카테고리의 다른 글

CSES 5. Range Queries  (0) 2021.07.21
CSES 3. Money Sum (1745)  (0) 2020.07.29
CSES 3. Edit Distance (1639)  (0) 2020.03.18
CSES 4. Road Reparation (1675)  (0) 2020.01.20
CSES 7. Stick Game (1729)  (0) 2020.01.19

출처: https://www.acmicpc.net/problem/15686


문제 설명

NxN grid위에 위치한 두 점(a, b), (c, d) 사이의 거리를 r = abs(a-c) + abs(b-d)로 정의한다.  문제에서는 각 집에서 가장 가까운 치킨집까지의 거리를 그 집의 치킨거리로 하고, 모든 집의 치킨 거리의 합을 도시의 치킨 거리로 한다.

치킨집의 수를 줄이고, 이때 도시의 치킨거리 최소값을 구하는 문제이다.


입력

N M

NxN

0 - 길, 1 - 집, 2 - 치킨집

출력

도시 치킨 거리 최소값


입력 예

5 2

0 2 0 1 0

1 0 1 0 0

0 0 0 0 0

2 0 0 1 1

2 2 0 1 2

출력 예

10

제약조건

2 <= N <=50 , 1 <= M <=13


문제 풀이

N x N Grid를 읽어 들이면서 집의 위치와 치킨집의 위치를 vector<pair<int, int>> 에 저장한다.

치킨집 배열에서 M개를 고르고, 이 때 각 집들에서 치킨 거리를 구하고, 그 합을 비교해서 최소값을 찾는다.

M개를 고르기 위해서, bitset을 이용해서, 치킨집들을 선택한다. 

프로그램 내용

더보기
...
bitset<MAX_M> bsets;
int min_dist = INT_MAX;	
vector<pair<int, int>> t_shops;
	
for(int b = 0; b < (1<<(int)shops.size()); ++b)
{
	if (__builtin_popcount(b) == tM) 
    {
    	bsets = b;   /// 해당하는 치킨집 조합 결정
    	for(int id=0; id< (int)shops.size();++id)
        {
        	if(bsets[id]) 
        	{
        		t_shops.push_back(shops[id]);
	        }				
		}
        int t_dist = 0;
        for(int id = 0; id<(int)house.size(); ++id)
        {
        	int h_dist = INT_MAX;
            int ht_dist = INT_MAX;
            int x, y;
            tie(x, y) = house[id];								
            for(int idn = 0; idn < (int)t_shops.size(); ++idn)
            {
    	        int t_x, t_y;
        	    tie(t_x, t_y) = t_shops[idn];									
            	int hh_dist = abs(x - t_x) + abs(y - t_y);
            	if( ht_dist > hh_dist)
            		ht_dist = hh_dist;
			}
            if (h_dist > ht_dist)	/// 각 집의 치킨거리 최소값
            	h_dist = ht_dist;
			t_dist += h_dist;
		}
	t_shops.clear();
	if( min_dist > t_dist)	/// 도시 치킨 거리 최소값
        min_dist = t_dist;
	}
}

 

관련된 문제

  • bitset :   USACO Trainging : 2.1.6 Healthy Holsteins ( link )

 

'Baekjoon Online Judge' 카테고리의 다른 글

BOJ 23970 알고리즘 수업 - 버블 정렬 3  (0) 2022.02.13
BOJ 2824 최대공약수  (0) 2021.12.03
BOJ 2903 - 중앙 이동 알고리즘  (0) 2020.01.28
BOJ 17404 - RGB거리 2  (0) 2019.12.10

출처:  https://cses.fi/problemset/task/1639


문제 설명

The edit distance between two strings is the minimum number of operations required to transform one string into the other.

The allowed operations are:

  • Add one character to the string.
  • Remove one character from the string.
  • Replace one character in the string.

For example, the edit distance between LOVE and MOVIE is 2, because you can first replace L with M, and then add I.

Your task is to calculate the edit distance between two strings.

입력 

The first input line has a string that contains n characters between A–Z.

The second input line has a string that contains m characters between A–Z.

출력

Print one integer: the edit distance between the strings.

입력 예

LOVE
MOVIE

출력 예

2

제약조건

1 <= n,m <= 5000


문제 풀이

두개의 문자열을 행과 열로 하는 테이블을 생각한다. src[i] == dest[j]는 변경할 필요가 없으며 값을 변경하지 않아도 된다. 문자열이 다르면, dist[i][j] = min({dist[i][j-1], dist[i-1][j], dist[i-1][j-1]) + 1 로 계속 변경해서 테이블을 완성한다.

프로그램 내용

더보기
...
for(int i=0; i <= m; ++i)
{
	for (int j=0; j <= n ; ++j)
	{
		if ( i == 0)
        	dist[i][j] = j; /// init for desStr
		else if ( j == 0)
        	dist[i][j] = i; /// init for srcStr
		else if ( srcStr[i-1] == desStr[j-1])
        	dist[i][j] = dist[i-1][j-1];
		else
        	dist[i][j] = 1 + min({	dist[i-1][j],      /// insert
									dist[i][j-1],      /// remove
									dist[i-1][j-1]});   /// replace
	}
}
...

 

Dynamic Programming link )

'CSES' 카테고리의 다른 글

CSES 3. Money Sum (1745)  (0) 2020.07.29
CSES 3. Rectangle Cutting (1744)  (0) 2020.07.28
CSES 4. Road Reparation (1675)  (0) 2020.01.20
CSES 7. Stick Game (1729)  (0) 2020.01.19
CSES 4. Road Construction (1676)  (0) 2020.01.13

출처: https://train.usaco.org/usacogate


문제 설명

Farmer John prides himself on having the healthiest dairy cows in the world. He knows the vitamin content for one scoop of each feed type and the minimum daily vitamin requirement for his cows. Help Farmer John feed the cows so they stay healthy while minimizing the number of scoops that a cow is fed.
Given the daily requirements of each kind of vitamin that a cow needs, identify the smallest combination of scoops of feed a cow can be fed in order to meet at least the minimum vitamin requirements.
Vitamins are measured in integer units. Cows can be fed at most one scoop of any feed type. It is guaranteed that a solution exists for all contest input data.

입력

Line 1: integer V (1 <= V <= 25), the number of types of vitamins

Line 2: V integers (1 <= each one <= 1000), the minimum requirement for each of the V vitamins that a cow requires each day

Line 3: integer G (1 <= G <= 15), the number of types of feeds available

Lines 4..G+3:
V integers (0 <= each one <= 1000), the amount of each vitamin that one scoop of this feed contains. The first line of these G lines describes feed #1; the second line describes feed #2; and so on.

출력

The output is a single line of output that contains:
 - the minimum number of scoops a cow must eat, followed by:
 - a SORTED list (from smallest to largest) of the feed types the cow is given

입력 예

4
100 200 300 400
3
50 50 50 50
200 300 200 300
900 150 389 399

출력 예

2 1 3


문제 풀이

모든 feed를 한번씩만 줄 수 있으므로, 전체 feed에서 가능한 모든 조합을 찾아서, 최소화 되는 조합을 출력한다.  feed 의 종류가 많지 않으므로( <= 15), bitset을 이용해서 필요한 조합을 찾는다. bitset<16> (0), ... bitset<16> (1<<numG) 다만, bitset으로 설정된 조합에서 작은 수들이 먼저 나오는 조합은 숫자로 변경하면, 더 큰 수가 된다.

프로그램 내용

더보기
...    
    for(int idx=0; idx < (1<<numG) ; ++idx)
    {
        vector <int> feeds(numV, 0);
        bitset<16> check(idx);

        for (int idx2=0; idx2 < numG ; ++idx2)
        {
            if( check[idx2] )
            {
                for(int idx3=0; idx3 < numV; ++idx3)
                {
                    feeds[idx3] += Feed_list[idx2][idx3];
                }
            }
        }

        /// check health : feeds vs V_req
        bool healthy = true;
        for(int idx2=0; idx2 < numV; ++idx2)
        {
            if ( feeds[idx2] < V_req[idx2])
            {
                healthy = false;
                break;
            }
        }

        if ( healthy 
        			&& check.count() < feed_count 
        			&& check.to_ulong() > feed_bit.to_ulong())
        {
            feed_count = check.count();
            feed_bit = check;
        }
    }
...

 

Chapter 2. Bigger Challenges (link)

+ Recent posts