bzoj 1061(线性规划+费用流)

12 篇文章 0 订阅
2 篇文章 0 订阅

1061: [Noi2008]志愿者招募

Time Limit: 20 Sec   Memory Limit: 162 MB
Submit: 3483   Solved: 2131
[ Submit][ Status][ Discuss]

Description

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

Input

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

Output

  仅包含一个整数,表示你所设计的最优方案的总费用。

Sample Input

3 3
2 3 4
1 2 2
2 3 5
3 3 2

Sample Output

14

HINT

1 ≤ N ≤ 1000,1 ≤ M ≤ 10000,题目中其他所涉及的数据均 不超过2^31-1。


解题思路:https://www.byvoid.com/blog/noi-2008-employee/

线性规划的两种做法,网络流或单纯性


#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
int n,m,len,S,T,ans;
const int INF=0x7fffffff;
int from[40000],to[40000],next[40000],h[40000],f[40000],w[40000];
bool b[1010];
int dis[1010],q[10000000],pre[1010];
int a[1010];


inline int read()
{
char y; int x=0,f=1; y=getchar();
while (y<'0' || y>'9') {if (y=='-') f=-1; y=getchar();}
while (y>='0' && y<='9') {x=x*10+int(y)-48; y=getchar();}
return x*f;
}


void insert(int x,int y,int flow,int v)
 {
  ++len; from[len]=x; to[len]=y; next[len]=h[x]; h[x]=len; f[len]=flow; w[len]=v; 
 }


bool spfa()
 {
  memset(b,true,sizeof(b)); b[S]=false;
  memset(dis,0x7f,sizeof(dis)); dis[S]=0;
  int tail=1,head=0; q[tail]=S;
  while (head<tail)
  {
  ++head; 
  int u=h[q[head]];
  while (u!=0)
  {
  if (f[u]>0 && dis[to[u]]>dis[q[head]]+w[u])
  {
  dis[to[u]]=dis[q[head]]+w[u];
  pre[to[u]]=u;
  if (b[to[u]])
  {
  b[to[u]]=false;
  ++tail; q[tail]=to[u];
}
}
u=next[u];
}
b[q[head]]=true;
 }
if (dis[T]<10000000) return true;else return false;
 }


void mcf()
{
int now=T; int mx=0x7fffffff;
while (now!=S)
{
mx=min(mx,f[pre[now]]);
now=from[pre[now]];
}
now=T;
while (now!=S)
{
  ans+=mx*w[pre[now]];
  f[pre[now]]-=mx; f[pre[now]^1]+=mx;
  now=from[pre[now]];
}
}


int main()
{
n=read(); m=read(); len=1; S=0; T=n+2;
for (int i=1;i<=n;++i)
{
a[i]=read(); 
int u=a[i]-a[i-1];
if (u>0)
{
insert(S,i,u,0); insert(i,S,0,0);
}else
 {
  insert(i,T,-u,0); insert(T,i,0,0);
 }
insert(i+1,i,INF,0);insert(i,i+1,0,0);
}
insert(n+1,T,a[n],0); insert(T,n+1,0,0);
insert(n+1,n,INF,0); insert(n,n+1,0,0);
for (int i=1;i<=m;++i)
{
int s,t,c; s=read(); t=read(); c=read();
insert(s,t+1,INF,c); insert(t+1,s,0,-c);
}
ans=0;
    while (spfa())
{
mcf();
}
printf("%d",ans);
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值