bzoj 1061 [Noi2008]志愿者招募

无源汇上下界最小费用可行流。

每天作为一个点。

每一天向下一天连一条上界为正无穷下界为该天所需人数费用为0的边。

对于每个志愿者,从他结束工作的后一天向开始工作的第一天连一条上界为正无穷下界为0费用为招募费的边。

在这个无源汇网络中,招募一个志愿者即产生一个Ti+1—>Si—>Si+1—>Si+2—>……—>Ti—>Ti+1的圈,使Si到Ti天的流量加1。

原图跑无源汇上下界最小费用可行流就行了。

类比poj3680,对于一个条件覆盖连续点问题,通常用将点依次相连再加边的方式,两题区别在于有上界正向连边最大流,有下界反向连边可行流。

 1 #include
 2 #include
 3 #include
 4 #include
 5 #include
 6 using namespace std;
 7 const int dian=1005;
 8 const int bian=30005;
 9 const int INF=0x3f3f3f3f;
10 int h[dian],nxt[bian],ver[bian],val[bian],cos[bian];
11 int d[dian],v[dian],minn[dian],with[dian],in[dian],out[dian];
12 int n,m,tot,aa,bb,cc,mf;
13 int S,T;
14 void add(int a,int b,int c,int d,int e){
15     tot++;ver[tot]=b;val[tot]=d-c;cos[tot]=e;nxt[tot]=h[a];h[a]=tot;
16     tot++;ver[tot]=a;val[tot]=0;cos[tot]=-e;nxt[tot]=h[b];h[b]=tot;
17     in[b]+=c;out[a]+=c;mf+=c*e;
18 }
19 bool tell(){
20     memset(v,0,sizeof(v));
21     memset(d,0x3f,sizeof(d));
22     memset(with,0,sizeof(with));
23     memset(minn,0x3f,sizeof(minn));
24     queue<int>q;
25     q.push(S);
26     v[S]=1;
27     d[S]=0;
28     while(!q.empty()){
29         int x=q.front();
30         q.pop();
31         v[x]=0;
32         for(int i=h[x];i;i=nxt[i]){
33             int y=ver[i];
34             if(d[y]>d[x]+cos[i]&&val[i]){
35                 d[y]=d[x]+cos[i];
36                 minn[y]=min(minn[x],val[i]);
37                 with[y]=i;
38                 if(!v[y]){
39                     v[y]=1;
40                     q.push(y);
41                 }
42             }
43         }
44     }
45     if(d[T]==0x3f3f3f3f)
46         return false;
47     return true;
48 }
49 int zeng(){
50     for(int i=T;i!=S;i=ver[with[i]^1]){
51         val[with[i]]-=minn[T];
52         val[with[i]^1]+=minn[T];
53     }
54     return d[T]*minn[T];
55 }
56 int dinic_cost(){
57     int r=0;
58     while(tell())
59         r+=zeng();
60     return r;
61 }
62 int main(){
63     memset(h,0,sizeof(h));
64     memset(nxt,0,sizeof(nxt));
65     memset(in,0,sizeof(in));
66     memset(out,0,sizeof(out));
67     tot=1,mf=0;
68     scanf("%d%d",&n,&m);
69     S=n+2,T=n+3;
70     for(int i=1;i<=n;i++){
71         scanf("%d",&aa);
72         add(i,i+1,aa,INF,0);
73     }
74     for(int i=1;i<=m;i++){
75         scanf("%d%d%d",&aa,&bb,&cc);
76         add(bb+1,aa,0,INF,cc);
77     }
78     for(int i=1;i<=n+1;i++){
79         if(in[i]>out[i])
80             add(S,i,0,in[i]-out[i],0);
81         else if(out[i]>in[i])
82             add(i,T,0,out[i]-in[i],0);
83     }
84     printf("%d",mf+dinic_cost());
85     return 0;
86 }

 

你可能感兴趣的:(bzoj 1061 [Noi2008]志愿者招募)