您的位置:首页 > 理论基础 > 计算机网络

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

2016-03-25 19:30 561 查看

[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

#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
using namespace std;
const int INF=100000010;
const int maxn=11010;
const int maxm=100010;
int cnt=1,fir[maxn],to[maxm],nxt[maxm],cap[maxm],val[maxm];
void addedge(int a,int b,int c,int v){
nxt[++cnt]=fir[a];to[cnt]=b;cap[cnt]=c;val[cnt]=v;fir[a]=cnt;
}
int N,M,S,T;
int dis[maxn],path[maxn],tot[maxn],vis[maxn];

queue<int>q;
int MCMF(){
int ret=0;
while(true){
memset(dis,127,sizeof(dis));dis[S]=0;
q.push(S);vis[S]=1;
while(!q.empty()){
int node=q.front();q.pop();vis[node]=0;
for(int i=fir[node];i;i=nxt[i])
if(cap[i]&&dis[to[i]]>dis[node]+val[i]){
dis[to[i]]=dis[node]+val[i];
path[to[i]]=i;
if(!vis[to[i]]){
vis[to[i]]=1;
q.push(to[i]);
}
}
}
if(dis[T]==2139062143)
break;

int p=T,f=INF;
while(p!=S){
f=min(f,cap[path[p]]);
p=to[path[p]^1];
}
ret+=dis[T]*f;p=T;
while(p!=S){
cap[path[p]]-=f;
cap[path[p]^1]+=f;
p=to[path[p]^1];
}
}
return ret;
}

int main(){
freopen("employee.in","r",stdin);
freopen("employee.out","w",stdout);
scanf("%d%d",&N,&M);
S=0;T=N+2;
for(int i=1;i<=N;i++)
scanf("%d",&tot[i]);
for(int i=1,a,b,c;i<=M;i++){
scanf("%d%d%d",&a,&b,&c);
addedge(a,b+1,INF,c);
addedge(b+1,a,0,-c);
}
for(int i=1;i<=N+1;i++){
int c=tot[i]-tot[i-1];
if(c>0){
addedge(S,i,c,0);
addedge(i,S,0,0);
}
if(c<0){
addedge(i,T,-c,0);
addedge(T,i,0,0);
}
if(i>1){
addedge(i,i-1,INF,0);
addedge(i-1,i,0,0);
}
}
printf("%d\n",MCMF());
return 0;
}


  然后又用线性规划。

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

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
const int maxr=11010;
const int maxc=1010;

const double eps=1e-10;
int n,m,nxt[maxc];
int N[maxr],B[maxr];
double a[maxr][maxr],v;
double b[maxr],c[maxr];

int SGN(double x){
return (x>eps)-(x<-eps);
}

void Init(){
B[0]=N[0]=0;v=0.0;
for(int i=1;i<=n;i++)N[++N[0]]=i;
for(int i=1;i<=m;i++)B[++B[0]]=i+n;
}

void Pivot(int l,int e){
b[e]=b[l]/a[l][e];
a[e][l]=1.0/a[l][e];
for(int i=1;i<=N[0];i++)
if(N[i]!=e)a[e][N[i]]=a[l][N[i]]/a[l][e];

int pre=0;
for(int i=1;i<=N[0];i++)
if(N[i]!=e&&SGN(a[e][N[i]])!=0)
{nxt[pre]=i;pre=i;}
nxt[pre]=0;

for(int i=1;i<=B[0];i++)
if(B[i]!=l){
b[B[i]]-=a[B[i]][e]*b[e];
a[B[i]][l]=-a[B[i]][e]*a[e][l];
for(int j=nxt[0];j;j=nxt[j])
if(N[j]!=e)a[B[i]][N[j]]-=a[B[i]][e]*a[e][N[j]];
}

v+=c[e]*b[e];
c[l]=-c[e]*a[e][l];
for(int i=1;i<=N[0];i++)
if(N[i]!=e)
c[N[i]]-=c[e]*a[e][N[i]];
for(int i=1;i<=N[0];i++)if(N[i]==e)N[i]=l;
for(int i=1;i<=B[0];i++)if(B[i]==l)B[i]=e;
}

void Simplex(){
while(true){
int e=maxr,l=maxr;
for(int i=1;i<=N[0];i++)
if(SGN(c[N[i]])>0&&e>N[i])e=N[i];

if(e==maxr)break;

double lam=-1;
for(int i=1;i<=B[0];i++)
if(SGN(a[B[i]][e])>0){
double tmp=b[B[i]]/a[B[i]][e];
if(lam==-1||SGN(lam-tmp)>0||SGN(lam-tmp)==0&&l>B[i])
{lam=tmp;l=B[i];}
}

Pivot(l,e);
}
}

int main(){
#ifndef ONLINE_JUDGE
freopen("employee.in","r",stdin);
freopen("employee.out","w",stdout);
#endif
scanf("%d%d",&n,&m);
for(int i=1,t;i<=n;i++){
scanf("%d",&t);
c[i]=t;
}

for(int i=1,l,r,t;i<=m;i++){
scanf("%d%d%d",&l,&r,&t);
for(int j=l;j<=r;j++)
a[i+n][j]=1;
b[i+n]=t;
}

Init();
Simplex();

printf("%d\n",(int)(v+0.5));
return 0;
}


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

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxr=10010;
const int maxc=1010;

int n,m,nxt[maxc];
int a[maxr][maxc];

void Pivot(int l,int e){
int pre=maxc-1;
for(int i=0;i<=n;i++)
if(a[l][i]!=0){nxt[pre]=i;pre=i;}
nxt[pre]=-1;

for(int i=0,t;i<=m;i++)
if(i!=l&&(t=a[i][e])){
a[i][e]=0;
for(int j=nxt[maxc-1];j!=-1;j=nxt[j])
a[i][j]+=t*a[l][j];
}
}

void Simplex(){
while(true){
int e=0,l=0;
for(int i=1;i<=n;i++)
if(a[0][i]>0){e=i;break;}
if(e==0)break;
for(int i=1;i<=m;i++)
if(a[i][e]<0&&(!l||a[l][0]>a[i][0]))
{l=i;}

Pivot(l,e);
}
}

int main(){
#ifndef ONLINE_JUDGE
freopen("employee.in","r",stdin);
freopen("employee.out","w",stdout);
#endif
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&a[0][i]);
for(int i=1,l,r,t;i<=m;i++){
scanf("%d%d%d",&l,&r,&t);
for(int j=l;j<=r;j++)
a[i][j]=-1;
a[i][0]=t;
}
Simplex();
printf("%d\n",a[0][0]);
return 0;
}


  这里的线性规划式子都是原式的对偶线性规划式。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: