OJ题号:
BZOJ1061题目大意:
有$n$个任务,$m$个志愿者,完成每个任务$i$至少需要$a_i$个人,每个人只有在$s_i$到$t_i$的时候有空,并需要被支付$c_i$的报酬,求完成所有任务的最小支出。思路:
“先挖空后补空”。 将每个时间抽象成点,并在时间轴的两端增加源汇$S$和$T$,每个相邻的时间点连一条边,容量为$inf-a_i$,费用为$0$。 对于每个人,连一条从$s_i$到$t_i+1$的容量为$inf$的边,费用为$c_i$。跑最小费用最大流即可。 第一遍的增广其实是没用的,因为费用是$0$,它的作用是把最早建的边中因为$inf$产生多余的容量去掉。 后面的几次增广就相当于补空。Rank1和Rank2为什么跑这么快?
![](https://images2017.cnblogs.com/blog/1155078/201709/1155078-20170901182222655-913654643.png)
1 #include2 #include 3 #include 4 #include 5 #include 6 inline int getint() { 7 char ch; 8 while(!isdigit(ch=getchar())); 9 int x=ch^'0';10 while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');11 return x;12 }13 const int inf=0x7fffffff;14 const int V=1002,E=22002;15 int s,t;16 struct Edge {17 int from,to,remain,cost;18 };19 Edge e[E];20 int sz;21 std::vector g[V];22 inline void add_edge(const int u,const int v,const int w,const int c) {23 e[sz]=(Edge){u,v,w,c};24 g[u].push_back(sz);25 sz++;26 }27 int a[V],p[V],d[V];28 bool inq[V];29 inline int Augment() {30 memset(a,0,sizeof a);31 a[s]=inf;32 std::fill(&d[1],&d[t+1],inf);33 d[s]=0;34 memset(inq,0,sizeof inq);35 std::queue q;36 q.push(s);37 inq[s]=true;38 while(!q.empty()) {39 int x=q.front();40 q.pop();41 inq[x]=false;42 for(unsigned i=0;i