互補鬆弛定理 12 7 16省隊集訓

2021-06-18 19:49:18 字數 2700 閱讀 4410

互補鬆弛定理

xi,yi分別為原問題和對偶問題的最優解,當且僅當

sigma(aij*yi | i=1~m)==cj or xi=0 j=1,2...,n

sigma(aij*xj | j=1~n)==bi or yi=0 i=1,2...m

題意:給乙個n*n

的矩陣,每次可以攻擊一列或者一行,攻擊一行的代價為

ai,攻擊一列的代價為

bi,要求每個格仔

i,j至少被攻擊

f[i][j]

次,要使得總代價最小,同時輸出方案

第一次接觸對偶定理就是這道題,那時候把對偶弄清楚了,但是互補鬆弛定理一直無法理解,不會輸出方案就不了了之了...

就對偶之後的建圖來說,其實比日本那道題要簡單一些

首先先把第一步的對偶定理做好,

建立n+n

個變數,lx1...lxn,ly1...lyn

分別表示每行每列攻擊了幾次

則我們的目標是

min約束條件

lxi+lyj>=f[i][j]

係數矩陣不好畫就自己yy

吧...

對偶之後化為

max約束條件提取

sigma(yi | i=(k-1)*n+1~k*n)<=ak

sigma(yi*n+k | i=1~n)<=bk

然後根據這個建圖

源點連出n

個點,每條邊容量為

ai,費用為0

n個點連向匯點,每條邊容量為

bi,費用為0

中間連n*n

條邊,,容量為

oo,費用為

f[i][j]

然後跑最大費用最大流,就可以了

但是很不爽的就是第二步,題解上講的模糊不清,就說在殘量網路跑一次最長路,根據互補鬆弛定理就可以得解,然後就一直無法理解...

現在重新來看,發現每個不等式至多有兩個變數,也就是說,可以用差分約束系統來做,然後瞬間就豁然開朗了...

先看互補鬆弛定理第乙個條件(我們可以發現網路流中間的n+n

個點都會代表原問題中的乙個變數)

它的意思就是說ai(bi)

流滿或者是

lxi(lyj)為0

然後第二個條件

這條邊沒有流量或者是

lxi+lyj==f[i][j]

同時注意有幾個隱含條件,lxi>=0,lyj>=0,lxi+lyj>=f[i][j]

然後這些式子都至於兩個變數有關,差分約束就很顯然了,

設d[i]=-lxi

就可以建圖了

我的做法是直接重建圖,跑差分約束,但std

貌似確實是直接在殘量網路上跑的,應該是簡化了建圖之類的吧

#include #include #include #include #include const int oo=1073741819;

using namespace std;

int d[20000],tail[20000],p[20000],v[20000],f[500][500],a[500][500];

int next[2000000],cost[2000000],sora[2000000],flow[2000000],po[2000000];

int st[2000000],s,t,n,ss,tot,s1;

bool spfa(int s,int t)

}} v[ne]=0;

} return d[t]>-oo;

}int widen()

tot+=sum;

for (int i=t;i!=s;i=sora[po[p[i]]])

return ans;

}void getans(int s)

}} v[ne]=0;

}// cout<

原始對偶版,直接從1s+進入0.3s(並且最大費用和最小費用只需修改鬆弛條件,越來越搞不懂原始對偶了...)

#include #include #include #include #include const int oo=1073741819;

using namespace std;

int d[20000],tail[20000],p[20000],v[20000],f[500][500],a[500][500];

int next[2000000],cost[2000000],sora[2000000],flow[2000000],po[2000000];

int w_time,st[2000000],s,t,n,ss,tot,s1,phi,flag[200000],ans;

bool spfa(int s,int t)

}} v[ne]=0;

} //cout}

} v[ne]=0; }}

void origin()

void link(int x,int y,int z,int c)

int a[500],b[500];

int main()

for (int i=1;i<=n;i++)

for (int i=1;i<=n;i++)

for (int j=1;j<=n;j++)

ans=0;

tot=0;

int sum=0;

for (phi=0;spfa(s,t);)

for (int tmp;w_time++,tmp=dfs(s,oo);) {

sum+=tmp;

//cout<

7 5省隊集訓 tree

思路 樹形dp。先求最大值。令s x 為x的子樹中葉子節點的數量。f x 為到x時 為先手走,先手能取到的值在子樹中排第f x 小。g x 為到x時 為後手走,後手能取到的值在子樹中排第f x 小。對f x 先手應該往哪個子樹走呢?對於x的一棵子樹y,如果進入,那麼最終答案就是這棵子樹中第g y 小...

FJOI省隊集訓 florida

省隊成員 大部分 都沒來.像我這種沙茶天天寫寫玄學演算法都能排在榜上面.果然正解寫掛的人遠比暴力拍對的人少啊.陸陸續續會補一些題解。不過有些題太神了可能補不上題解 有n個物品,兩個袋子a和b。若物品i與j放在同乙個袋子裡,那麼代價為t i j 保證t i i 0,t i j t j i 乙個袋子的代...

7 10省隊集訓夢工廠

思路 題面真心長.單調棧維護上凸殼即可 設sum i 為前i道工序的複雜度之和,g i 為第i個快樂最早開始生產的時間。因為我們要保證沒有兩個快樂同時出現在同一道工序,所以 g i g i 1 max sum j f i 1 sum j 1 f i 然後就是像斜率優化的過程了 sum j f i 1...