线性规划||网络流(费用流):COGS 288. [NOI2008] 志愿者招募

[NOI2008] 志愿者招募

输入文件:employee.in   输出文件:employee.out   简单对比
时间限制:2 s   内存限制:512 MB

【问题描述】

申奥成功后,布布经过不懈努力,终于成为奥组委下属公司人力资源部门的主管。布布刚上任就遇到了一个难题:为即将启动的奥运新项目招募一批短期志愿者。经过估算,这个项目需要N 天才能完成,其中第i 天至少需要Ai 个人。
布布通过了解得知,一共有M 类志愿者可以招募。其中第i 类可以从第Si 天工作到第Ti 天,招募费用是每人Ci 元。新官上任三把火,为了出色地完成自己的工作,布布希望用尽量少的费用招募足够的志愿者,但这并不是他的特长!于是布布找到了你,希望你帮他设计一种最 优的招募方案。

【输入格式】

输入文件的第一行包含两个整数N, M,表示完成项目的天数和可以招募的志愿者的种类。
接下来的一行中包含N 个非负整数,表示每天至少需要的志愿者人数。
接下来的M 行中每行包含三个整数Si, Ti, Ci,含义如上文所述。为了方便起见,我们可以认为每类志愿者的数量都是无限多的。

【输出格式】
输入文件中仅包含一个整数,表示你所设计的最优方案的总费用。

【输入样例】
3 3
2 3 4
1 2 2
2 3 5
3 3 2
【输出样例】
14

【样例说明】
招募3 名第一类志愿者和4 名第三类志愿者。
【数据规模和约定】
30%的数据中,1 ≤ N, M ≤ 10,1 ≤ Ai ≤ 10;
100%的数据中,1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均
不超过2^31-1。

  https://www.byvoid.com/zhs/blog/noi-2008-employee

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <queue>
 5 using namespace std;
 6 const int INF=100000010;
 7 const int maxn=11010;
 8 const int maxm=100010;
 9 int cnt=1,fir[maxn],to[maxm],nxt[maxm],cap[maxm],val[maxm];
10 void addedge(int a,int b,int c,int v){
11     nxt[++cnt]=fir[a];to[cnt]=b;cap[cnt]=c;val[cnt]=v;fir[a]=cnt;
12 }
13 int N,M,S,T;
14 int dis[maxn],path[maxn],tot[maxn],vis[maxn];
15 
16 queue<int>q;
17 int MCMF(){
18     int ret=0;
19     while(true){
20         memset(dis,127,sizeof(dis));dis[S]=0;
21         q.push(S);vis[S]=1;
22         while(!q.empty()){
23             int node=q.front();q.pop();vis[node]=0;
24             for(int i=fir[node];i;i=nxt[i])
25                 if(cap[i]&&dis[to[i]]>dis[node]+val[i]){
26                     dis[to[i]]=dis[node]+val[i];
27                     path[to[i]]=i;
28                     if(!vis[to[i]]){
29                         vis[to[i]]=1;
30                         q.push(to[i]);
31                     }
32                 }
33         }
34         if(dis[T]==2139062143)
35             break;
36         
37         int p=T,f=INF;
38         while(p!=S){
39             f=min(f,cap[path[p]]);
40             p=to[path[p]^1];
41         }
42         ret+=dis[T]*f;p=T;
43         while(p!=S){
44             cap[path[p]]-=f;
45             cap[path[p]^1]+=f;
46             p=to[path[p]^1];
47         }
48     }
49     return ret;
50 }
51 
52 int main(){
53     freopen("employee.in","r",stdin);
54     freopen("employee.out","w",stdout);
55     scanf("%d%d",&N,&M);
56     S=0;T=N+2;
57     for(int i=1;i<=N;i++)
58         scanf("%d",&tot[i]);
59     for(int i=1,a,b,c;i<=M;i++){
60         scanf("%d%d%d",&a,&b,&c);
61         addedge(a,b+1,INF,c);
62         addedge(b+1,a,0,-c);
63     }
64     for(int i=1;i<=N+1;i++){
65         int c=tot[i]-tot[i-1];
66         if(c>0){
67             addedge(S,i,c,0);
68             addedge(i,S,0,0);
69         }
70         if(c<0){
71             addedge(i,T,-c,0);
72             addedge(T,i,0,0);
73         }
74         if(i>1){
75             addedge(i,i-1,INF,0);
76             addedge(i-1,i,0,0);
77         }
78     }
79     printf("%d\n",MCMF());
80     return 0;
81 }

 

 

  然后又用线性规划。

  额,松弛型先天不足,数组开不了,无法通过,再学一下吧。

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 #include <cmath>
 5 using namespace std;
 6 const int maxr=11010;
 7 const int maxc=1010;
 8 
 9 const double eps=1e-10;
10 int n,m,nxt[maxc];
11 int N[maxr],B[maxr];
12 double a[maxr][maxr],v;
13 double b[maxr],c[maxr];
14 
15 int SGN(double x){
16     return (x>eps)-(x<-eps);
17 }
18 
19 void Init(){
20     B[0]=N[0]=0;v=0.0;
21     for(int i=1;i<=n;i++)N[++N[0]]=i;
22     for(int i=1;i<=m;i++)B[++B[0]]=i+n;
23 }
24 
25 void Pivot(int l,int e){
26     b[e]=b[l]/a[l][e];
27     a[e][l]=1.0/a[l][e];
28     for(int i=1;i<=N[0];i++)
29         if(N[i]!=e)a[e][N[i]]=a[l][N[i]]/a[l][e];
30     
31     int pre=0;
32     for(int i=1;i<=N[0];i++)
33         if(N[i]!=e&&SGN(a[e][N[i]])!=0)
34             {nxt[pre]=i;pre=i;}
35     nxt[pre]=0;
36             
37     for(int i=1;i<=B[0];i++)
38         if(B[i]!=l){
39             b[B[i]]-=a[B[i]][e]*b[e];
40             a[B[i]][l]=-a[B[i]][e]*a[e][l];
41             for(int j=nxt[0];j;j=nxt[j])
42                 if(N[j]!=e)a[B[i]][N[j]]-=a[B[i]][e]*a[e][N[j]];
43         }
44         
45     v+=c[e]*b[e];
46     c[l]=-c[e]*a[e][l];
47     for(int i=1;i<=N[0];i++)
48         if(N[i]!=e)
49             c[N[i]]-=c[e]*a[e][N[i]];
50     for(int i=1;i<=N[0];i++)if(N[i]==e)N[i]=l;
51     for(int i=1;i<=B[0];i++)if(B[i]==l)B[i]=e;
52 }
53 
54 void Simplex(){
55     while(true){
56         int e=maxr,l=maxr;
57         for(int i=1;i<=N[0];i++)
58             if(SGN(c[N[i]])>0&&e>N[i])e=N[i];
59             
60         if(e==maxr)break;        
61         
62         double lam=-1;
63         for(int i=1;i<=B[0];i++)
64             if(SGN(a[B[i]][e])>0){
65                 double tmp=b[B[i]]/a[B[i]][e]; 
66                 if(lam==-1||SGN(lam-tmp)>0||SGN(lam-tmp)==0&&l>B[i])
67                     {lam=tmp;l=B[i];}
68             }
69         
70         Pivot(l,e);    
71     }
72 }
73 
74 int main(){
75 #ifndef ONLINE_JUDGE
76     freopen("employee.in","r",stdin);
77     freopen("employee.out","w",stdout);
78 #endif
79     scanf("%d%d",&n,&m);
80     for(int i=1,t;i<=n;i++){
81         scanf("%d",&t);
82         c[i]=t;
83     }
84         
85     for(int i=1,l,r,t;i<=m;i++){
86         scanf("%d%d%d",&l,&r,&t);
87         for(int j=l;j<=r;j++)
88             a[i+n][j]=1;
89         b[i+n]=t;
90     }
91     
92     Init();
93     Simplex();
94     
95     printf("%d\n",(int)(v+0.5));
96     return 0;    
97 }

   这个程序可以AC,但解法并不具有共性啊……

 1 #include <iostream>
 2 #include <cstring>
 3 #include <cstdio>
 4 using namespace std;
 5 const int maxr=10010;
 6 const int maxc=1010;
 7 
 8 int n,m,nxt[maxc];
 9 int a[maxr][maxc];
10 
11 
12 void Pivot(int l,int e){
13     int pre=maxc-1;
14     for(int i=0;i<=n;i++)
15         if(a[l][i]!=0){nxt[pre]=i;pre=i;}
16     nxt[pre]=-1;
17             
18     for(int i=0,t;i<=m;i++)
19         if(i!=l&&(t=a[i][e])){
20             a[i][e]=0;
21             for(int j=nxt[maxc-1];j!=-1;j=nxt[j])
22                 a[i][j]+=t*a[l][j];
23         }
24 }
25 
26 void Simplex(){
27     while(true){
28         int e=0,l=0;
29         for(int i=1;i<=n;i++)
30             if(a[0][i]>0){e=i;break;}
31         if(e==0)break;        
32         for(int i=1;i<=m;i++)
33             if(a[i][e]<0&&(!l||a[l][0]>a[i][0]))
34                 {l=i;}
35         
36         Pivot(l,e);    
37     }
38 }
39 
40 int main(){
41 #ifndef ONLINE_JUDGE
42     freopen("employee.in","r",stdin);
43     freopen("employee.out","w",stdout);
44 #endif
45     scanf("%d%d",&n,&m);
46     for(int i=1;i<=n;i++)
47         scanf("%d",&a[0][i]);
48     for(int i=1,l,r,t;i<=m;i++){
49         scanf("%d%d%d",&l,&r,&t);
50         for(int j=l;j<=r;j++)
51             a[i][j]=-1;
52         a[i][0]=t;
53     }
54     Simplex();
55     printf("%d\n",a[0][0]);
56     return 0;    
57 }

  这里的线性规划式子都是原式的对偶线性规划式。

posted @ 2016-03-25 19:30  TenderRun  阅读(290)  评论(0编辑  收藏  举报