day10 1208 翻硬幣(遞推)
1208. 翻硬幣
小明正在玩一個“翻硬幣”的遊戲。
桌上放著排成一排的若干硬幣。我們用*
表示正面,用o
表示反面(是小寫字母,不是零)。
比如,可能情形是:**oo***oooo
如果同時翻轉左邊的兩個硬幣,則變為:oooo***oooo
現在小明的問題是:如果已知了初始狀態和要達到的目標狀態,每次只能同時翻轉相鄰的兩個硬幣,那麼對特定的局面,最少要翻動多少次呢?
我們約定:把翻動相鄰的兩個硬幣叫做一步操作。
輸入格式
兩行等長的字串,分別表示初始狀態和要達到的目標狀態。
輸出格式
一個整數,表示最小操作步數
資料範圍
輸入字串的長度均不超過100。
輸入樣例1:
**********
o****o****
輸出樣例1:
5
輸入樣例2:
*o**o***o***
*o***o**o***
輸出樣例2:
1
思路
除第一與最後兩枚硬幣外,想要變動一個硬幣有2個選擇 ,那就是翻動這個硬幣和他的左邊或右邊那枚硬幣,如此一來 若我們認準改變狀態只翻動該硬幣和它右邊的硬幣,即可傻瓜式操作,如果當前硬幣與目標狀態不一致就翻動該硬幣和它右邊的硬幣。
PS:
由於題目保證有解,所以無需考慮最後一個硬幣,若不保證有解,那麼最後一個幣在操作一番後,狀態與目標狀態是否一致就成了有無解的標準。
細節解釋
我們可以這樣思考這個題目,我們如何使翻硬幣次數最少就能達到最終目的呢?
不妨假設我們隨便翻,如果這樣,我們每改變一個位置的硬幣,都會影響周圍兩個硬幣的狀態,且只能影響其中一個(要麼前面的,要麼後面的),這樣的話我們即使使用暴力列舉完成也無法保證其次數最少,
怎麼辦讓它次數最少呢?
很簡單,我們每翻一個硬幣就把他的狀態固定下來,即我每翻一個硬幣,就保證前面的硬幣和目標硬幣狀態一樣了,這樣的話次數就最少了…
仔細思考上面的思路,並不難理解,想明白上面的大體思路我們再來看怎樣去翻
,假設第二個位置和目標狀態不同,我怎麼去翻,我一定要去翻第二個硬幣來使得它與目標狀態相同,也可以理解為如果當前判斷的硬幣狀態與目標硬幣狀態不同,我就翻當前狀態的硬幣,和下一個硬幣,為什麼要這樣呢,為啥第二個位置不同就不能翻第二個硬幣和第一個硬幣呢?
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
char[] source = scanner.nextLine().toCharArray();
char[] target = scanner.nextLine().toCharArray();
int res = 0;
//由於題目保證有解,故最後一枚硬幣經過前面的操作後一定是相同的了,不用比較了,
//故i<source.length-1即可,否則寫成i<source.length,則turn(source,i+1)時,i+1將出現下標越界
for(int i = 0;i < source.length - 1;i++){
if(source[i] != target[i]){//當前硬幣與目標狀態不同,翻轉它和它右邊的硬幣
turn(source,i);
turn(source,i+1);
res++;//操作次數加一
}
}
System.out.println(res);
}
//用於翻轉硬幣
private static void turn(char[] source, int i) {
if(source[i] =='*') source[i] = 'o';
else source[i] = '*';
}
}