一如既往地咕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日少女-网易云