1. 程式人生 > >[NOI2008]誌願者招募

[NOI2008]誌願者招募

最大流 img -a loading 什麽 printf front load memset

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 }

技術分享

[NOI2008]誌願者招募