題目連結: https://tioj.ck.tp.edu.tw/problems/1014

# 內容

有 n 個從左而右排成一列的地鼠洞,相鄰兩個洞距離皆為 1。在每個洞各有一出現周期固定的地鼠,且地鼠被打一次之後就不會再出現。你在第一個洞的左邊距離 1 處,你每秒可走 1 的距離。現在給你每個地鼠的周期,求若要打完所有地鼠至少要花多久?

# 思路

dp[s][i]

  • s 代表地鼠的狀態,如果第 x 位是 1 代表第 x 支還活着
  • i 代表最後是敲下哪一個位置的地鼠 (結尾)
    dp[s][i] = min{ 0<=k<n | dp[在敲i之前][k結尾]+行走時間+一段時間到t[i]的倍數 }

轉換 (進位) 為倍數的方式有兩種:

  1. ((time1)/T[i]+1)T[i]((time - 1) / T[i] + 1) * T[i] time -1 就是擔心 time 本身就是 T [i] 的倍數
  2. ceil(time/T[i])T[i]ceil(time / T[i]) * T[i](ceil 就是無條件進位)

# 程式碼

#include<bits/stdc++.h>
#define INF 999999999
using namespace std;
int dp[(1<<16)][17],T[17],ans,n;
int main()
{
    ios_base::sync_with_stdio(0); cin.tie(0);
    cin >> n;
    for(int i = 0; i < n; i++) cin >> T[i];
    fill(&dp[0][0],&dp[1<<n][n],INF); ans = INF;
    dp[0][0] = 1;
    for(int s = 1; s < (1<<n); s++)
        for(int i = 0; i < n; i++) {
            if(!(s&(1<<i))) continue; // 已經被打死了 QQ
            for(int j = 0; j < n; j++) {
                int time = dp[s&~(1<<i)][j]+abs(j-i);  // 原本 + 移動至 i
                int p = ceil((double)time/ T[i] )* T[i];  // 等待至整數倍
                dp[s][i] = min(dp[s][i],p);
            }
            if(s == (1<<n)-1) ans = min(ans,dp[s][i]);
        }
    cout << ans << '\n';
}
更新於 閱讀次數

用實際行動犒賞爆肝的我😀

Zrn Ye LinePay

LinePay