• 线性规划||网络流(费用流):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
    ",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
    ",(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
    ",a[0][0]);
    56     return 0;    
    57 }

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

    尽最大的努力,做最好的自己!
  • 相关阅读:
    js刷新
    getHibernateTemplate()为NUll
    struts2+hibernate+spring+jquery返回json List列表
    windowopen
    web配置详解
    缓存
    uuid-不好之处
    多对多转化一对多
    多对多拆成两个 多对一
    我的github地址账号和密码
  • 原文地址:https://www.cnblogs.com/TenderRun/p/5320702.html
Copyright © 2020-2023  润新知