1. 程式人生 > 其它 >演算法競賽進階指南_打卡_題解_0x00

演算法競賽進階指南_打卡_題解_0x00

①:最短Hamilton路徑:狀壓dp
https://www.acwing.com/problem/content/93/

給定一張 n 個點的帶權無向圖,點從 0∼n−1 標號,求起點 0 到終點 n−1 的最短 Hamilton 路徑。
Hamilton 路徑的定義是從 0 到 n−1 不重不漏地經過每個點恰好一次。
輸入格式
第一行輸入整數 n。
接下來 n 行每行 n 個整數,其中第 i 行第 j 個整數表示點 i 到 j 的距離(記為 a[i,j])。
對於任意的 x,y,z,資料保證 a[x,x]=0,a[x,y]=a[y,x] 並且 a[x,y]+a[y,z]≥a[x,z]。
輸出格式
輸出一個整數,表示最短 Hamilton 路徑的長度。
\(1≤n≤20\)


\(0≤a[i,j]≤10^{7}\)

剛開始想了一下最小生成樹,後來發現每個點每條邊只能走一遍且沒有回頭路,最小生成樹就可以×掉了。
我們觀察到資料範圍n不大,可以暴力()
我們於是就可以設立\(0\)~\(2^{20}\)的數,以其二進位制表示式代表該點有無被探測過。
很容易,我們可以得到一個數組\(f[i][j]\)\(i\)為目前於點\(i\)停止,\(j\)為目前為止被探測的狀態。
我們可以得到狀態轉移方程\(f[i][j]=min(f[i][j],f[k][p]+mp[k][i])\)。狀態\(i\)由狀態\(p\)轉移過來,而\(mp[i][j]\)代表從\(i\)點到\(j\)點的花費。
輸出\(min(f[0...20][2^{20}-1])\)

即可。

②:起床困難綜合症:模擬,貪心,位運算
https://www.acwing.com/problem/content/1000/

drd 的防禦戰線由 n 扇防禦門組成。
每扇防禦門包括一個運算 op 和一個引數 t,其中運算一定是 OR,XOR,AND 中的一種,引數則一定為非負整數。
如果還未通過防禦門時攻擊力為 x,則其通過這扇防禦門後攻擊力將變為 x op t。
最終 drd 受到的傷害為對方初始攻擊力 x 依次經過所有 n 扇防禦門後轉變得到的攻擊力。
由於 atm 水平有限,他的初始攻擊力只能為 0 到 m 之間的一個整數(即他的初始攻擊力只能在 0,1,…,m 中任選,但在通過防禦門之後的攻擊力不受 m 的限制)。
為了節省體力,他希望通過選擇合適的初始攻擊力使得他的攻擊能讓 drd 受到最大的傷害,請你幫他計算一下,他的一次攻擊最多能使 drd 受到多少傷害。

我們假設對於\(x\)二進位制位上的每一位,考慮其是否能取\(0\)\(1\)。若能取,我們留下標記。

如何取判斷第\(i\)位能取?
我們只要列舉為\(0\)\(1\)的情況,將其進行上述的第\(i\)\(n\)次運算,觀察答案是否使我們的總貪心值小於等於\(m\),如果小於,則合法,否則不取。

核心程式碼

    for(int i=maxx;i>=1;--i){
        int Tbit;
        int temp=pow(2,i-1);
        for(int k=1;k<=2;++k){
            Tbit=Ubit[k];
            for(int j=1;j<=n;++j){
                if(bit[j][0]==-1){
                    Tbit&=bit[j][i];
                }
                if(bit[j][0]==-2){
                    Tbit|=bit[j][i];
                }
                if(bit[j][0]==-3){
                    Tbit^=bit[j][i];
                }
            }
            if(Tbit==1){
                N+=temp;
                ori+=temp*Ubit[k];
                if(ori>m){
                    ori-=temp*Ubit[k];
                    N-=temp;
                }
                break;
            }
        }
    }