[NOI2008 志愿者招募]

[关键字]:图论 网络流

[题目大意]:有n天每天需要ai个志愿者,有m种志愿者每种可已从第xi天干到第yi天花费为ci(不是志愿者吗),问最小花费。

[分析]:弱菜没做出来,Orz BYvoid神牛http://www.byvoid.com/blog/noi-2008-employee/

[代码]:

View Code
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;

const int MAXN=1100;
const int INF=1684300900;

struct node
{
int x,y,next,cost,op,d;
}e[MAXN*40];
int first[MAXN],pre[MAXN*40];
int n,m,tot,S,T,ans;
int a[MAXN],d[MAXN];
bool b[MAXN];
queue<int> q;

void Add(int x,int y,int c,int d)
{
e[++tot].y=y;
e[tot].x=x;
e[tot].d=d;
e[tot].cost=c;
e[tot].op=tot+1;
e[tot].next=first[x];
first[x]=tot;
e[++tot].y=x;
e[tot].x=y;
e[tot].d=0;
e[tot].cost=-c;
e[tot].op=tot-1;
e[tot].next=first[y];
first[y]=tot;
}

void Init()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;++i)
scanf("%d",&a[i]);
for (int i=1;i<=m;++i)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
Add(x,y+1,z,INF);
}
S=0,T=n+2;
for (int i=1;i<=n+1;++i)
{
int temp=a[i]-a[i-1];
if (temp>0) Add(S,i,0,temp); else Add(i,T,0,-temp);
if (i>1) Add(i,i-1,0,INF);
}
}

bool SPFA()
{
memset(b,0,sizeof(b));
memset(d,100,sizeof(d));
d[S]=0,b[S]=1,q.push(S),pre[S]=-1;
while (!q.empty())
{
int u=q.front();
b[u]=0,q.pop();
for (int i=first[u];i;i=e[i].next)
if (d[e[i].y]>d[u]+e[i].cost && e[i].d>0)
{
d[e[i].y]=d[u]+e[i].cost;
pre[e[i].y]=i;
if (!b[e[i].y])
{
b[e[i].y]=1;
q.push(e[i].y);
}
}
}
return d[T]<INF;
}

void Find()
{
int Min=INF;
for (int i=pre[T];i!=-1;i=pre[e[i].x])
Min=min(Min,e[i].d);
for (int i=pre[T];i!=-1;i=pre[e[i].x])
{
e[i].d-=Min;
e[e[i].op].d+=Min;
ans+=Min*e[i].cost;
}
}

int main()
{
Init();
while (SPFA()) Find();
printf("%d\n",ans);
return 0;
}



你可能感兴趣的:(2008)