一如既往地咕spa
某地區有 \(m\) 座煤礦,其中第 \(i\) 號礦每一年產量爲 \(a_i\) 噸。code
有一箇舊發電廠,每一年需用煤 \(b\) 噸(將剛好 \(b\) 噸煤運給舊發電廠),每一年維護費用爲 \(h\) 元,每噸原煤從第 \(i\) 號礦運到舊發電廠的運費爲 \(C_{i0}\)(\(i=1,2,\cdots,m\))。rem
現規劃新建一個發電廠,\(m\) 座煤礦每一年開採的原煤除了供給舊發電廠的 \(b\) 噸,其他所有供給新發電廠。現有 \(n\) 個備選的廠址。若在第 \(j\) 號備選廠址建新廠,每一年維護費用爲 \(h_j\) 元。每噸原煤從第 \(i\) 號礦運到 \(j\) 號備選廠址的運費爲 \(C_{ij}\)(\(i=1,2,\cdots,m\);\(j=1,2,\cdots,n\))。get
求總費用的最小值,以及在該最小費用下,新發電廠的廠址編號最小是多少。string
數據規模 \(n\le50\),\(m\le50000\),\(b\le10000\)it
這道題能夠直接貪心,可是既然要學帶悔貪心,用帶悔貪心作也不是不行 awaio
\(n\) 不大,能夠對每一個廠址都計算一次「將新發電廠建在該處的最小花費」。因而只須要決策煤的分配。模板
記 \(c_i\) 爲每噸煤從煤礦 \(i\) 運到舊發電廠的代價,\(c_i'\) 爲運到新發電廠的代價。class
先考慮簡單的狀況,假如每一個煤礦只有一噸煤。queue
由於舊發電廠必需要 \(b\) 噸煤,不妨先隨便安排把這 \(b\) 噸湊滿。
而後剩下的煤直接分配給新發電廠嗎?顯然是不必定最優的——考慮當前煤礦 \(i\) 的一噸煤:
條件就是 \(c_i+c_j'< c_i'+c_j\) 等價於
因而維護當前供給舊發電廠的煤礦的 \(c_j-c_j'\) 的大根堆,若是堆頂能夠被煤礦 \(i\) 替代,則替代。因爲替代出的 \(j\) 是當前堆中最大的,因此 \(j\) 不可能反過來又替代掉堆中其餘的煤礦。
可是如今煤礦不止有一噸煤怎麼辦?因而咱們聯想到帶悔貪心(模擬費用流)的模板題中「每一個洞能夠容納多隻老鼠」的狀況,用堆維護 pair
,維護 \(c_j-c_j'\) 的大根堆,以及該類煤有多少噸。
詳見代碼。
/*Lucky_Glass*/ #include<queue> #include<vector> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; inline int Rint(int &r){ int b=1, c=getchar(); r=0; while(c<'0' || '9'<c) b=c=='-'?-1:b, c=getchar(); while('0'<=c && c<='9') r=(r<<1)+(r<<3)+(c^'0'), c=getchar(); return r*=b; } const int N=55, M=5e4+10; typedef pair<int, int> pii; int m, varB, varH, n; int num[M], aryh[N], aryc[M][2]; int main(){ Rint(m), Rint(varB), Rint(varH), Rint(n); for(int i=1; i<=m; i++) Rint(num[i]); for(int i=1; i<=n; i++) Rint(aryh[i]); for(int i=1; i<=m; i++) Rint(aryc[i][0]); long long anscost=0; int anspos=-1; for(int i=1; i<=n; i++){ //把新工廠建在 i 位置 for(int j=1; j<=m; j++) Rint(aryc[j][1]); long long total=varH+aryh[i]; int rem=varB; //to new - to old priority_queue<pii, vector<pii>, greater<pii> > que; for(int j=1; j<=m; j++){ //tmp: 工廠j還剩多少單位 //use: 工廠j運給舊工廠多少單位 int tmp=num[j], use=0; if(rem) //舊工廠不夠 if(rem>=tmp){ //所有運給舊工廠 total+=1ll*aryc[j][0]*tmp; rem-=tmp, use=tmp, tmp=0; } else{ //還有一些剩餘 total+=1ll*aryc[j][0]*rem; tmp-=rem, use=rem, rem=0; } while(!que.empty() && tmp){ //嘗試用 j 代替本來供應給舊工廠的 top if(que.top().first>=aryc[j][1]-aryc[j][0]) break; pii tp=que.top(); que.pop(); int now=min(tmp, tp.second); //替代了 now 單位 use+=now, tp.second-=now, tmp-=now; if(tp.second) que.push(tp); total+=1ll*now*tp.first+1ll*now*aryc[j][0]; } if(tmp) total+=1ll*tmp*aryc[j][1]; //其餘剩餘所有給新工廠 if(use) que.push(make_pair(aryc[j][1]-aryc[j][0], use)); //運給舊工廠的 use 單位準備反悔 } if(~anspos){ if(total<anscost) anscost=total, anspos=i; } else anscost=total, anspos=i; } printf("%d\n%lld\n", anspos, anscost); return 0; }
> Link 餘命3日少女-網易雲