[백준 #1907, Python] 탄소화합물
우히히 우히히 처음으로 내힘으로 하루만에 실버 5풀었다 우히히우히히 잘풀었든 못풀었든 매우 기쁘다

제목보고; 아 화공학도로써 이건 못참지 학고 선택했음 ㅋㅅㅋ.. 예제에 반응식들이 심히 거슬리긴 했지만,, 내가 반례 생각하겠다고 아는척하면서 공식끌어쓴것들은 다 탄화수소 계열이라 생성물 4개라서 조건 위배되서 코드 에러가 계속났다.. 난 내 잘못인지도 몰랐지..우히히..
아무튼! 여기서 중복순열로 방정식의 계수를 찾을 수 있다는 것을 알았다!
from itertools import product으로 반복하는 객체?를 만들어서 하는 것 같다.
for x in product(range(a,b), range(a,b))
이렇게 하면 (a,a)부터 (b-1,b-1)까지 생성된다! 그때 if문을 생성해서 우리의 조건(방정식에 맞는값을 찾으면 되는 것!)
[문제]
한 마디루 계수 맞추기
세 가지 종류의 원자 - C, H, O로만 이루어진 화합물을 탄소 화합물이라고 한다. 우리는 아래와 같은 단순한 화학식의 계수를 맞추어 균형을 주려고 한다.
<분자> + <분자> = <분자>
여기서 <분자>란 아래와 같은 형식으로 되어 있는 문자열을 말한다.
<원자>[숫자]<원자>[숫자] … <원자>[숫자]
각각의 분자는 적어도 하나 이상의 원자로 구성되어 있고, 각각의 원자 뒤에 따라붙게 되는 숫자는 그 원자가 몇 번 나타나는가 하는 것이다. 숫자는 2 이상 9 이하이며, 숫자가 표시되지 않은 경우는 그 원자가 한 번만 나타났다는 뜻이다.
예를 들어 HC3OH2와 같은 문자열은 분자이고, 이는 H 3개, C 3개, O 1개로 되어 있는 분자가 된다. C2HOH + CH = C5O2H4와 같은 식이 우리가 관심이 있는 화학식이 된다.
어떤 화학식이 균형이 있다는 것은, 등호(=)를 기준으로 왼쪽에 있는 각각의 원자의 개수와 오른쪽에 있는 각각의 원자의 개수가 같을 때를 말한다. 예를 들어 C+CH=C2H와 같은 식이 균형 있는 화학식이 된다.
만일 어떤 화학식이 균형이 있지 않다면, 적절한 계수를 주어 화학식의 균형을 맞출 수 있다. 즉 각 <분자>가 여러 개 있는 것으로 생각한다는 것이다. 예를 들어 C+CC=CCCCC와 같은 화학식은 C + 2 ( CC ) = CCCCC 와 같이 1, 2, 1의 계수를 주어 균형을 맞출 수 있다는 것이다.
탄소 화합물 분자로만 이루어진 <분자> + <분자> = <분자> 형태의 화학식이 주어지면, 적절히 계수를 맞추어서 균형 있는 화학식으로 만드는 프로그램을 작성하시오. 단, 계수는 1 이상 10 이하로만 한정하도록 하자.
[코드]
from itertools import product
equation=input().split("=")
equation += equation[0].split("+")
equation.pop(0)
equation.reverse()
#A+B->C의 반응식에서, 내 equation은 [B,A,C] 순서로 담겨있다
result =[]
for element in equation:
atom={}
#딕서너리에 각 반응물 '원소':개수로 설정
for i in range(len(element)):
if element[i].isdigit():
#만약 숫자라면 앞에문자개수가 숫자만큼이다.
#'원소':1일때, -1해주고 곱해주면 에러가 생기고,
#중복을 방지하기 위해 1*숫자 -1 로 설정해줬다.
#숫자 나오기 전에, 문자가 카운트됬으므로 -1해줘야함
atom[element[i-1]]=atom.get(element[i-1])+(1* int(element[i]))-1
else:
atom[element[i]] = atom.get(element[i],0) + 1
result.append(atom)
#중복순열->(1,1,1) 부터 (10,10,10)
answer=[]
for x in product(range(1,11),range(1,11),range(1,11)):
X2=x[0]
X1=x[1]
X3=x[2]
left_C= X1*result[1].get('C',0)+X2*result[0].get('C',0)
left_O= X1*result[1].get('O',0)+X2*result[0].get('O',0)
left_H= X1*result[1].get('H',0)+X2*result[0].get('H',0)
right_C= X3*result[2].get('C',0)
right_O= X3*result[2].get('O',0)
right_H= X3*result[2].get('H',0)
if left_C-right_C == 0 and left_H - right_H ==0 and left_O-right_O ==0:
answer+=[(X1, X2, X3)]
#(X1이 가장 작은놈)이 답이되고->X1동일시 X2작은놈
answer.sort()
for j in answer[0]:
print(j, end=" ")
엄청 긴 코드지만, 요약하자면༼ つ ◕_◕ ༽つ
1. =을 기준으로 반응물/생성물을 나눠준다
2. +를 기준으로 반응물 끼리도 나누어준다
3. 여기는 좀 불필요한 단계지만 내가 생각하기 쉽게 하기위해서(생성물이 먼저 오는건 못참지 ) 반응물-생성물 순으로
리스트가 담길 수 있게 수정해줬는데, 완벽하지는 않아서 순서를 잘 기억해야한다.
4. 딕셔너리 이용 -> 만약 문자라면 key에 문자, value에 1씩 더해서 갯수를 샌다. 만약, 숫자라면 앞의 원소의 개수를 나타내줘야하는데, 여기서 get을 써서 에러를 방지하였다. 이때, H3의 경우는 H가 반복문을 먼저 돌면서 'H' :1이 된다.
처음에는, 여기서 -1을 하고 뒤에 3을 곱해줄려 했는데, 그러면 0*3이니까 안먹는다 -> 바보같이 *'ㅂ'*~!
그래서 아예 1*3(숫자)해주고, H문자가 반복문 더해서 중복으로 1되어있던거를 빼줬다!
5. 중복순열 영차영차 써서 좌변(반응물)-우변(생성물)=0이면 밸런스 맞을때니까, 그때의 x값을 list에 담아주었다.
마지막으로, sort로 딕셔너리 순으로 배치해서 조건에 맞는 값을 출력하면 끝!