-
1050번 : 물약알고리즘/백준(acmicpc.net) 문제풀이 2022. 1. 9. 14:15반응형
https://www.acmicpc.net/problem/1050
1050번: 물약
첫째 줄에 LOVE를 1만큼 만드는데 드는 비용의 최솟값을 출력한다. 만약 그 값이 1,000,000,000보다 크다면 1000000001을 출력한다. 만약 LOVE를 만드는 것이 불가능 하다면 -1을 출력한다.
www.acmicpc.net
N개의 주어진 재료와 M개의 조합식(또는 새로운 재료)를 갖고 LOVE를 만들 수 있는지 , 만들 수 있다면 그 최솟값은 무엇인지 구하는 문제이다.
아이디어 :
우선, 주어진 재료들의 이름과 비용은 map을 사용해서 나타낼 수 있다.
조합식들은 항상 a=k1*m1+k2*m2+... 꼴로 나타낼 수 있으며 파싱을 잘 해서 {계수, 재료이름} 꼴로 나타낼 수 있다.M제한이 50이고, 모든 식을 한번씩 돌면 하나의 식은 무조건 완성시킬 수 있다. (답이 안나오는 경우는 한 개의 식도 완성시킬 수 없으며, 이는 더이상 완성시킬 수 있는 식이 존재하지 않는다는 말이다.)
* 여기서 완성시킨다 라는 말은 조합식에서 필요한 재료들을 다 만들 수 있다는 말이다.
* a=1*b+2*c 라는 식이 있고, 주어진 재료로 b=1, c=2가 있으면 a=5로 식을 완성시킬 수 있다.따라서 모든 식을 다 검색하는 것을 모든 식만큼 반복하면 M*M번만에 정답을 무조건 찾을 수 있다.
구현 :
먼저 재료 문자열을 저장할 map이 필요하다. 한번이라도 등장한 문자열은 무조건 이 map에 속하게 된다.
문자열을 key로 두고, value는 최소 비용 또는 -1이 담기게 된다. -1은 재료를 만들 수 없음을 의미한다.다음으로 식을 저장할 공간이 필요하다. 이차원 벡터로 선언했고, 각 공간마다 {계수, 재료이름}이 들어간다.
단, 벡터의 첫 공간에는 {0, 만들 재료}가 무조건 들어가게 된다.
선언은 vector<vector<pair<long long,string> > > ex(51); 으로 했다.조합식의 파싱이 관건이다.
(만들 재료)=(재료1계수)(재료1)+(재료2계수)(재료2)..+(재료n계수)(재료n) 꼴로 주어지므로
처음 '='까지 string을 쌓아서 벡터의 첫 공간에 넣어주고, 그 다음 인덱스를 읽어서 계수로 저장해준 다음,
다음 '+' 또는 string이 끝날때까지 string을 쌓아서 벡터에 push_back({재료n계수, 재료n}) 해준다.
파싱 중에 새로운 문자열이 있으면 재료문자열 map에도 추가한다.파싱이 끝나면 모든 식을 돌면서 식을 완성시킨다. 이 과정을 M번 더 반복 해주면 답을 찾을 수 있다.
코드 :
#include <bits/stdc++.h> using namespace std; using ll=long long int; map<string, ll> m; vector<vector<pair<ll,string> > > ex(51); int main(){ ios::sync_with_stdio(0); cin.tie(0); int N,M; cin>>N>>M; for(int i=0; i<N; ++i){ string str; cin>>str; ll a; cin>>a; m[str]=a; } for(int i=0; i<M; ++i){ string str; cin>>str; int idx=0; string s=""; while(str[idx]!='='){ s+=str[idx++]; } ex[i].push_back({0,s}); if(m.find(s)==m.end()){ m[s]=-1; } while(1){ string temp=""; idx++; if(idx>=str.size()) break; ll coef=str[idx++]-'0'; while(idx<str.size() && str[idx]!='+'){ temp+=str[idx++]; } ex[i].push_back({coef,temp}); if(m.find(temp)==m.end()){ m[temp]=-1; } } } for(int i=0; i<M; ++i){ for(int j=0; j<M; ++j){ ll cnt=0; string goal=ex[j][0].second; bool flag=true; for(int k=1; k<ex[j].size(); ++k){ if(m[ex[j][k].second]==-1){ flag=false; break; } cnt+=m[ex[j][k].second]*ex[j][k].first; if(cnt>1000000000) cnt=1000000001; } if(flag){ if(m[goal]==-1) m[goal]=cnt; else m[goal]=min(m[goal],cnt); } } } if(m.find("LOVE")==m.end() || m["LOVE"]==-1){ cout << "-1\n"; } else{ cout << m["LOVE"] << '\n'; } }
반응형'알고리즘 > 백준(acmicpc.net) 문제풀이' 카테고리의 다른 글
18185번 : 라면 사기 (Small) (0) 2022.01.09 1071번 : 소트 (0) 2022.01.09 1047번 : 울타리 (0) 2022.01.09 1074번 : Z (0) 2018.07.11 11729번 : 하노이 탑 이동 순서 (0) 2018.06.18