窮舉法的問題實踐。
有4個砝碼,總重量40g ,砝碼的重量是整數,請找出4個砝碼在天平上秤重時,可以秤出1g ~ 40g 的重物。
所以要先找出這是4顆砝碼 {w1、w2、w3、w4}。
條件是
1.4顆加起來重量是40g
2.每一顆重量不相同。
3.可以利用這4顆砝碼秤出 1g ~ 40g的重物
因為天平是兩端。所以秤重量可以利用..
兩邊總和相等,例如:1 + 4 = 2 + W 這樣的排列就可以秤出W = 3 。
或是單邊等重,例如:1 + 4 = W 這樣可以秤出 W = 5。
或是集中在單邊,例如:1 + 2 + 3 + 4 = W 這樣可以秤出 W = 10
因此要找出4顆可以秤出1g ~ 40g (W) 的重物都有解,
也就是W = w1 + w2 + w3 + w4 。
這時再看看,當砝碼沒用上時。 例如上面案例W = 5 的,就只用了兩個砝碼
也有砝碼全部用在單邊,例如上面案例W = 10的。
也或者是當作減項的,例如上面案例W = 3的,就是利用 1 + 4 - 2(減項),來得到W = 3。
因此可以導出一個公式, 有用上(1)、沒用上(0)、當作減項 (-1)
W = w1*a1 + w2*a2 + w3*a3 + w4*a4
其中 a1、a2、a3、a4 可能的值是 { 1、0、-1 }
只要最後能符合這個公式,那就算是找到這4顆砝碼了。
之後在列出秤重的結果。
static void Main(string[] args)
{
//窮舉法列出多種組合
int flag;
int x;
int d1, d2, d3, d4;
int w1 = 0, w2 = 0, w3 = 0, w4 = 0;
#region 檢查砝碼
for (int i = 1; i <= 40; i++)
{
for (int j = i + 1; j <= 40 - i; j++)//內圈起始值為外圈加1,這樣數字就不會重複計算。
{
for (int k = j + 1; k <= 40 - i - j; k++)
{
int m = 0;
if ((m = 40 - i - j - k) >= k)
{
for (flag = 1, x = 1; x < 41 && flag == 1; x++)
{
//假如重物放天平左邊,法碼可放置在:-1:天平左邊(減項);1天平右邊;0不用該法碼
for (flag = 0, d1 = 1; d1 > -2; d1--)
{
for (d2 = 1; d2 > -2 && flag == 0; d2--)
{
for (d3 = 1; d3 > -2 && flag == 0; d3--)
{
for (d4 = 1; d4 > -2 & flag == 0; d4--)
{
if (x == i * d1 + j * d2 + k * d3 + m * d4)
{
flag = 1;
}
}
}
}
}
}
if (flag == 1)
{
Console.Write("砝碼重量為:{0} {1} {2} {3}", i, j, k, m);
Console.ReadLine();
w1 = i;
w2 = j;
w3 = k;
w4 = m;
}
}
}
}
}
#endregion
#region 處理秤重結果
string left = "";
string right = "";
for (int i = 1; i <= 40; i++)
{
for (int a1 = -1; a1 <= 1; a1++)
{
for (int a2 = -1; a2 <= 1; a2++)
{
for (int a3 = -1; a3 <= 1; a3++)
{
for (int a4 = -1; a4 <= 1; a4++)
{
if (i == a1 * w4 + a2 * w3 + a3 * w2 + a4 * w1)
{
bool f = true;
left = i + "";
switch (a1) //依據狀態調整顯示算式
{
case -1: //狀態-1 等號左邊
left = left + " + " + w4;
break;
case 1: //狀態1 等號右邊
if (f)
{
right = right + w4; //如果是第一項,數值不用有 + 號
}
else
{
right = right + " + " + w4; //已經有數值之後都要+號
}
f = false; //已經有數值,標記變更為false
break;
}
switch (a2) //依據狀態調整顯示算式
{
case -1: //狀態-1 等號左邊
left = left + " + " + w3;
break;
case 1: //狀態1 等號右邊
if (f)
{
right = right + w3; //如果是第一項,數值不用有 + 號
}
else
{
right = right + " + " + w3; //已經有數值之後都要+號
}
f = false; //已經有數值,標記變更為false
break;
}
switch (a3) //依據狀態調整顯示算式
{
case -1: //狀態-1 等號左邊
left = left + " + " + w2;
break;
case 1: //狀態1 等號右邊
if (f)
{
right = right + w2; //如果是第一項,數值不用有 + 號
}
else
{
right = right + " + " + w2; //已經有數值之後都要+號
}
f = false; //已經有數值,標記變更為false
break;
}
switch (a4) //依據狀態調整顯示算式
{
case -1: //狀態-1 等號左邊
left = left + " + " + w1;
break;
case 1: //狀態1 等號右邊
if (f)
{
right = right + w1; //如果是第一項,數值不用有 + 號
}
else
{
right = right + " + " + w1; //已經有數值之後都要+號
}
f = false; //已經有數值,標記變更為false
break;
}
Console.WriteLine(left + " = " + right);
}
left = "";
right = "";
}
}
}
}
}
#endregion
Console.ReadLine();
}
}
水滴可成涓流,涓流可成湖泊大海。
汲取累積知識,將知識堆積成常識;將常識探究成學識;將學識簡化為知識;授人自省。