題意:給m類志願者,第i個志願者從第 l[ i ] 天工作到第 r[ i ] 天,費用為c[ i ]。每種志願者可以選擇無限多人。
每一天都有給定的最少志願者數目要求a[ i ],求費用最小的選擇方案,輸出費用。
思路:明顯是一道線性規劃可以解決的問題,但我不會寫單純型。聽溪哥說線性規劃都有網路流的等價形式,不過我在網上沒有找到,知道的dalao可以給我留個言嗎。
進入正題:
假設第i種志願者選xi人,則有方程
a1 * x1 >= a[ 1 ]
a2 * x2 >= a[ 2 ]
a3 * x3 >= a[ 3 ]
an * xn >= a[ n ]
除此之外在開頭新增 方程0 = 0。在結尾新增 0 = 0.
將a[ i ] 移動到 方程左端後變為網路流流量平衡的形式。n + 1個方程對應n+1個節點。
我們注意到每個變數在方程中連續出現,則差分之後每個變數在兩個方程**現,並且乙個係數為正,乙個係數為負。
這就對應網路流中的一條邊,這是這個演算法的精髓所在,如果xi多次出現的話對應網路流中的多條邊,則這個演算法直接涼涼。
而常數項就與原點或匯點連邊。
這裡留個坑,一般形式的線性規劃如何轉化為網路流求解。以後要是做到這類題來補上。
#include using namespace std;
typedef long long ll;
const ll maxn = 10000;
const ll maxm = 1000000;
const ll inf = 0x3f3f3f3f3f3f3f3f;
struct mcmf
void add(ll x,ll y,ll cap,ll c)
bool spfa(ll s,ll t)
d[s] = 0;
vis[s] = true;
q.push(s);
while(!q.empty())}}
}if(pre[t] == -1)return false;
else return true;
}ll mincost(ll s,ll t,ll &cc)
for(ll cure = pre[t];cure != -1;cure = pre[ ver[cure^1] ])
flow += mn;
}return flow;
}} g;
ll a[maxn];
int main()
else if( cur < 0 )
}if( a[n] ) g.add( ss,n+1,a[n],0 );
for( ll i = 1;i <= m;i++ )
for( ll i = 1;i <= n;i++ )
ll cost;
ll maxflow = g.mincost(ss,tt,cost);
printf("%lld",cost);
return 0;
}
bzoj 1061 志願者招募
明顯的線性規劃網路流,據說當時考場上就1個人a了?a i j 表示第i種志願者第j天是否工作 p i 表示第i種志願者的人數 sigma a i x p i need x 補充函式y i 則sigma a i x p i need x y x 差分,start i 表示第i種志願者開始工作的時間,e...
BZOJ 1061, 志願者招募
傳送門 最小化招聘給定不同型別志願者,以滿足每日不同人數要求的費用總和。由線性規劃轉化為最小費用最大流來處理。一般按如下步驟進行操作 新增鬆弛變數,將不等號都變為等號。分別用下乙個式子減去上乙個式子,如果每個變數只出現了兩次且符號一正一負,那麼可以轉化為費用流。對於每個式子建立乙個點,那麼每個變數對...
BZOJ 1061 志願者招募
思路 可以用不等式的改裝變成費用流.將不等式列出,如果有負的常數,那麼就從等式連向t,如果是正的就從s連向等式,流量為常數,費用為0。如果是變數,那麼找出都有這個變數的兩個等式,從負的連向正的流量為inf的邊,如果有費用,那就再加上費用。1 include2 include3 include4 in...