1. 程式人生 > 其它 >筆記 - 0/1分數規劃

筆記 - 0/1分數規劃

圖論 0/1分數規劃的筆記與題目

題目

  • 放棄測試 模板 0/1 分數規劃

  • sightseeing cows 0/1 分數規劃 + SPFA判負環
    這題好像不能用 dinkelbach迭代法

  • 沙漠之王 0/1 分數規劃 + Prim

    關於 dinkelbach 迭代法完虐二分法的這件事

    《進階指南》中關於 0/1分數規劃介紹的末尾, 挖了個 dinkelbach演算法 的坑
    我遂網上衝浪了一下, 找到了這篇 優秀的大佬的令人orz的部落格

    有多快

    放棄測試 中, dinkelbach 以五倍的速度完虐二分法
    在此題也同樣穩定地五倍吊打著

    核心思想

    (我講不好..具體看上面的那篇部落格)
    函式 \(f(x)=\sum A_ic_i-x\sum B_ic_i\)

    其實是個直線
    求出 \(x\) 對應的 \(f_{x_{max}}\) 後, 二分演算法僅僅判斷了\(f_{x_{max}}\)\(0\) 的關係
    但其實將 \(f_{x_{max}}\) 利用起來, 找到 \(f_{x_{max}}\) 所在的那條直線, 然後將 \(x\) 移到這條直線的截距上去, 就可以實現極速定位

    程式碼

    double dinkelbach(){             
        double x=0, ans, p, q;
        while(true){
            ans=x, p=0, q=0;
            REP(i, 0, n) dis[i]=INF, vis[i]=false; dis[1]=0;
            
            REP(_, 1, n){                           // Prim O(N^2)
                int u=0;
                REP(v, 1, n) if(!vis[v] && dis[v] < dis[u]) u=v;
                vis[u] = true;
                if(u!=1) p += c[pre[u]][u], q += d[pre[u]][u];
    
                REP(v, 1, n) if(!vis[v] && dis[v] > c[u][v]-d[u][v]*x)
                    dis[v] = c[u][v]-d[u][v]*x, pre[v]=u;
            }
            x = p/q;                                // 直接移動到截距上
            if(fabs(ans-x)<eps) break;              // 沒有更優了, 退出
        }
        return ans;                                 // 即為最終答案
    }
    

    但似乎 dinkelbach 並不能完全取代二分, 可能在某些場景前者並不適用, 所以最好兩種方法都掌握.
    迭代法不適用的場景之一: 0/1分數規劃 + SPFA判負環