Statement
เพื่อความเข้าใจที่ตรงกัน ขอทบทวนปัญหาและตั้งชื่อตัวแปรต่าง ๆ ดังนี้ มีส่วนผสมสำหรับทำเปอร์เก็ต ชนิด แต่ละชนิดมีค่าความเปรี้ยว (sourness) และความขม (bitterness) สำหรับความเปรี้ยวของส่วนผสมชนิดที่ จะเขียนแทนด้วย และค่าความขมของส่วนผสมชนิดที่ เขียนแทนด้วย โดย
จงเลือกส่วนผสมอย่างน้อย ชนิดอย่างไรก็ได้ ให้ค่าความต่างระหว่างผลคูณของค่า ที่เลือก กับผลบวกของค่า ที่เลือก มีค่าน้อยที่สุดเท่าที่เป็นไปได้
Solution
เนื่องจากจำนวนของส่วนผสมมีจำนวนน้อย ดังนั้นสามารถทดลองเลือกส่วนผสมของทุก ๆ ซับเซตและหาค่าผลต่างระหว่างผลคูณของค่าความเปรี้ยวและผลบวกของค่าความขมที่น้อยที่สุดเท่าที่เป็นไปได้
กำหนด 3 ตัวแปรสำหรับการแก้ปัญหาด้วยฟังก์ชันเรียกตัวเอง (recursive function) ดังนี้
- เลขดัชนี (index) ของส่วนผสมชนิดต่อไปซึ่งเราจะใช้เลขนี้เป็นตัวตัดสินใจว่าจะเลือกหรือไม่เลือกส่วนผสมชนิดที่
- ค่าผลคูณความเปรี้ยวรวม (sourness) ที่เคยเลือกมา
- ค่าผลรวมความขม (bitterness) ที่เคยเลือกมา
ในการเรียก recursive function แต่ละครั้ง เราจะสร้างการตัดสินใจอย่างใดอย่างหนึ่งใน ทางเลือกดังนี้
- ทางเลือกที่เราจะไม่หยิบส่วนผสมชนิดที่ และไปพิจารณาการตัดสินลักษณะนี้กับส่วนผสมชนิดต่อไป
- อีกทางเลือกคือเราจะทำการหยิบส่วนผสมชนิดที่ (ซึ่งเมื่อหยิบมาแล้ว เราต้องเปลี่ยนแปลงค่าความเปรี้ยวรวมกับค่าความขมรวมด้วย) จากนั้นก็ไปพิจารณาการตัดสินใจลักษณะนี้กับส่วนผสมชนิดต่อไป
Code
#include <stdio.h> #define MAXN 10 int n, s[MAXN], b[MAXN], best = 1000000000; int diff(int x, int y) { return x < y ? y - x : x - y; } void recur(int i, int sourness, int bitterness) { if (i == n) { if (bitterness > 0 && diff(sourness, bitterness) < best) best = diff(sourness, bitterness); } else { recur(i + 1, sourness, bitterness); // กรณีไม่เลือกส่วนผสมชนิดที่ i recur(i + 1, sourness * s[i], bitterness + b[i]); // กรณีที่เลือกส่วนผสมชนิดที่ i } } int main(void) { scanf("%d", &n); for (int i = 0; i < n; ++i) scanf("%d%d", &s[i], &b[i]); recur(0, 1, 0); printf("%d\n", best); return 0; }