1061: [Noi2008]志愿者招募
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
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。
确实,只有这里有比较详细的解释了
蒟蒻的网络流很垃圾。。于是看了好一会
因为我们知道网络流肯定都是流量平衡的,所以只要最大流量了,那么肯定就能满足所有的等式------也就是能把所有的常数项满足,就满足条件了
贴一下代码
(很多都是抄的):
#include<cstdio>
#include<cstring>
const int N=1005;
const int MAX=1<<30;
int n,m;
int st1,ed1;
struct qq
{
int x,y;
int last;
int z,z1,other;
}s[50005];
int num,last[N];
int ans=0;
int init1 (int x,int y,int z,int z1)
{
num++;
s[num].x=x;s[num].y=y;s[num].z=z;s[num].z1=z1;
s[num].last=last[x];
last[x]=num;
return num;
}
void init (int x,int y,int z,int z1)
{
int num1=init1(x,y,z,z1),num2=init1(y,x,0,-z1);
s[num1].other=num2;s[num2].other=num1;
return ;
}
int dis[N],from[N],q[N];
bool q1[N];
bool SPFA ()
{
memset(dis,127,sizeof(dis));
memset(from,-1,sizeof(from));
memset(q1,false,sizeof(q1));
int st=1,ed=2;
dis[st1]=0;from[st1]=-1;q1[st1]=true;q[st]=st1;
while (st!=ed)
{
int x=q[st];
for (int u=last[x];u!=-1;u=s[u].last)
{
int y=s[u].y;
if (s[u].z>0&&dis[x]+s[u].z1<dis[y])
{
from[y]=u;
dis[y]=dis[x]+s[u].z1;
if (q1[y]==false)
{
q1[y]=true;
q[ed]=y;
ed++;
if (ed>=N-1) ed=1;
}
}
}
q1[x]=false;
st++;
if (st>=N-1) st=1;
}
if (from[ed1]!=-1) return true;
return false;
}
int mymin (int x,int y)
{
return x<y?x:y;
}
void add ()
{
int x=from[ed1];
int f=MAX;
while (x!=-1)
{
f=mymin(f,s[x].z);
x=from[s[x].x];
}
x=from[ed1];
while (x!=-1)
{
ans=ans+f*s[x].z1;
s[x].z-=f;
s[s[x].other].z+=f;
x=from[s[x].x];
}
}
int main()
{
num=0;memset(last,-1,sizeof(last));
st1=1003;ed1=st1+1;
int l=0;
scanf("%d%d",&n,&m);
for (int u=1;u<=n;u++)
{
int x,a;
scanf("%d",&a);
x=a-l;l=a;
if (x>0) init(st1,u,x,0);
else init(u,ed1,-x,0);//常数
init(u+1,u,MAX,0);//Y值
}
init(n+1,ed1,l,0);
for (int u=1;u<=m;u++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
init(x,y+1,MAX,z);//X值
}
while (SPFA()==true) add();
printf("%d\n",ans);
return 0;
}
做完这题,我知道了:可以根据流量平衡来进行网络流的建图,以后还有多多练习网络流