[NOI2008]志愿者招募

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为什么跑这么快?

 

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cctype>
 4 #include<vector>
 5 #include<cstring>
 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<int> 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<int> 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<g[x].size();i++) {
43             Edge &y=e[g[x][i]];
44             if(y.remain&&(d[x]+y.cost<d[y.to])) {
45                 d[y.to]=d[x]+y.cost;
46                 a[y.to]=std::min(a[x],y.remain);
47                 p[y.to]=g[x][i];
48                 if(!inq[y.to]) {
49                     q.push(y.to);
50                     inq[y.to]=true;
51                 }
52             }
53         }
54     }
55     return a[t];
56 }
57 inline int EdmondsKarp() {
58     int mincost=0;
59     while(int flow=Augment()) {
60         for(int i=t;i!=s;i=e[p[i]].from) {
61             e[p[i]].remain-=flow;
62             e[p[i]^1].remain+=flow;
63         }
64         mincost+=d[t]*flow;
65     }
66     return mincost;
67 }
68 int main() {
69     int n=getint(),m=getint();
70     s=0,t=n+1;
71     add_edge(s,1,inf,0);
72     add_edge(1,s,0,0);
73     for(int i=1;i<=n;i++) {
74         add_edge(i,i+1,inf-getint(),0);
75         add_edge(i+1,i,0,0);
76     }
77     for(int i=1;i<=m;i++) {
78         int s=getint(),t=getint(),c=getint();
79         add_edge(s,t+1,inf,c);
80         add_edge(t+1,s,0,-c);
81     }
82     printf("%d\n",EdmondsKarp());
83     return 0;
84 } 

 

posted @ 2017-09-01 18:24  skylee03  阅读(120)  评论(0编辑  收藏  举报