time limit: 5 sec memory limit: 64 mb
submit: 1131 solved: 640
[submit][status][discuss]
乙個整數表示聯盟裡所有球隊收益之和的最小值。
3 31 0 2 1
1 1 10 1
0 1 3 3
1 22 3
3 143
分析:很妙的idea.
首先要能想到用最小費用最大流求解. 為什麼呢?把比賽當作點,每一場比賽有兩種結果,那麼就可以認為容量為1. 要使得收益最小,加上費用,就是求最小費用最大流了.
但是確定不了每場比賽的收益.
乙個非常巧妙的做法:
我們考慮費用的增量:多贏一場比賽產生的收益。
即(c(w + 1)^2 + d(l − 1)^2 ) − (cw^2 + dl^2 ) = 2wc − 2ld + c + d。
對於第i支隊伍,假設後m場中i參加的有x場,那麼最初w = win,
l = lose + x,之後每贏一場w + +,l − −。我們從第i支隊伍的點向匯連x條邊,
分別代表第i支隊伍贏了j場比賽時相對贏j − 1場時收益的增量。由於增量一定
越來越大(平方嘛),所以流量最先流過的一定是費用較小的邊,即j最小的邊。
答案即所有隊伍最初收益+最小費用最大流的費用。
費用遞增模型可以採用拆邊的方式跑費用流. 先確定最初狀態,保證以後的費用都是遞增的,這是演算法正確性的保證!
#include #include#include
#include
#include
using
namespace
std;
const
int maxn = 10010,inf = 0x7fffffff
;int
n,m,win[maxn],lose[maxn],c[maxn],d[maxn];
inta[maxn],b[maxn],ans,s,t,vis[maxn],vis2[maxn];
int head[maxn],to[maxn * 6],nextt[maxn * 6],w[maxn * 6],cost[maxn * 6],tot = 2
;void add(int x,int y,int z,int
p)bool
spfa()}}
}return d[t]
}int dfs(int u,int
f)
int res = 0
; vis2[u] = 1
;
for (int i = head[u];i;i =nextt[i])
}return
res;
}void
dinic()
intmain()
for (int i = 1; i <= n; i++)
ans += win[i] * win[i] * c[i] + lose[i] * lose[i] *d[i];
for (int i = 1; i <= m; i++)
dinic();
printf(
"%d\n
",ans);
return0;
}
JSOI2009 bzoj1449 球隊收益
description input output 乙個整數表示聯盟裡所有球隊收益之和的最小值。首先假設全輸,然後給每場比賽分配乙個贏家,每個隊伍每多贏一場多獲得的收益作為費用。但是有乙個問題,如何保證每次走的是對應的邊?也就是,如何保證贏第一場的時候增加的收益是贏一場減贏零場,而不是贏兩場減贏一場?...
bzoj1449 JSOI2009 球隊收益
傳送門 感覺就是費用流呀。可以發現這道題與之前的費用流題有所不同,因為乙個球隊不論輸還是贏都會獲得收益。這裡就要用到乙個技巧,我們可以假裝比賽雙方都輸,然後修改贏的就ok辣。然後就是每個人向終點連邊,這裡的費用隨著流量的變化而變化,所以我們要用到拆邊法。考慮乙個人從贏win i 次 輸lose i ...
BZOJ1449 JSOI2009 球隊收益
bzoj luogu 在乙個籃球聯賽裡,有 n 支球隊,球隊的支出是和他們的勝負場次有關係的,具體來說,第i支球隊的賽季總支出是 c i times x 2 d i times y 2,d i le c i 其中 x,y 分別表示這只球隊本賽季的勝負場次。現在賽季進行到了一半,每只球隊分別取得了 a...