[TIOJ] 1014打地鼠

題目連結:http://tioj.ck.tp.edu.tw/problems/1014
  看來是我輕忽了,以前是看別人的code才會寫的,現在想想位元DP我從來好像也只寫過這麼一題而已QQ,我因為這題今天差點陷入低潮,一直錯、懷疑自己之類的,中途還差點想要去看解,不過最後守著最後一絲堅持送上去之後出乎意料的AC了XD。
  不靠自己解出這題不行,我必須變得更強!
  如果知道位元DP的觀念的話很容易寫出轉移式:dp[s][i] = dp[s/i][j]+abs(j-i)+@@@,由於每隻地鼠都有一定的周期才會出來,所以到i隻的時間就必須要是T[i]的倍數,這裡就必須動點腦筋了,我的寫法是dp[s][i] = ceil((dp[s/i][j]+abs(j-i))/T[i])*T[i],不過網路上其他人的寫法則是((dp[s/i][j]+abs(j-i)-1)/T[i]+1)*T[i]。
  另外,設定邊界dp[0][0] = 1,之後會比較好處理,算是一種熟悉位元DP的人能夠信手拈來的技巧吧,但是我一開始沒想到就去算了dp[1<<i][i]當作邊界了QQ
  看來我還有很多技巧要學!!
#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;
            for(int j = 0; j < n; j++)
            {
                int tt = dp[s-(1<<i)][j]+abs(j-i);
                int p = ceil((double)tt/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';
}

留言

這個網誌中的熱門文章

Shellshock.io從入門到上手(針對單狙)(沒有圖片、影片版本)

[TIOJ] 1007燈泡問題

[TIOJ] 1080 逆序數對