bzoj1061【Noi2008】志愿者招募

题意:http://www.lydsy.com/JudgeOnline/problem.php?id=1061

   有n天m种人,每天用a[i]个人,每种人工作时间为[l,r],费用为c[i],求最小费用

sol  :orz byvoid https://www.byvoid.com/blog/noi-2008-employee/

   一种神奇的线性规划单纯形做法QAQ然而我不会

   不过可以转成有上下界的最小费用可行流

   将每一天看成一个点,源点为1,汇点为n+1

   第i天向第i+1天连一条(i,i+1,a[i],inf,0)的边

   对于一种志愿者,从l[i]+1向r[i]连一条(l[i]+1,r[i],0,inf,c[i])的边

   跑上下界最小费用可行流,S到T不连边

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int Mx1=20010;
const int Mx2=1000010;
int S,T,n,m,tot;
int ver[Mx2],nxt[Mx2],head[Mx1],a[Mx1],c[Mx1],s[Mx1],e[Mx1],pos[Mx1],nag[Mx1];
long long edge[Mx2],cost[Mx2],dis[Mx1],with[Mx1],minn[Mx1];
bool vis[Mx1];
void add(int u,int v,int dd,int c)
{
    tot++;
    nxt[tot]=head[u];head[u]=tot;ver[tot]=v;cost[tot]=c;edge[tot]=dd;
    tot++;
    nxt[tot]=head[v];head[v]=tot;ver[tot]=u;cost[tot]=-c;edge[tot]=0;
}
void clear()
{
    memset(vis,0,sizeof(vis));
    memset(dis,0x3f,sizeof(dis));
    memset(minn,0x3f,sizeof(minn));
    memset(with,0,sizeof(with));
}
bool Spfa() 
{
    clear();
    queue <int> q; q.push(S);
    vis[S]=1,dis[S]=0;
    while(!q.empty())
    {
        int u=q.front(); q.pop(); vis[u]=0;
        for(int i=head[u];i;i=nxt[i])
        {
            int v=ver[i];
            if(dis[v]>dis[u]+cost[i]&&edge[i]>0)
            {
                dis[v]=dis[u]+cost[i]; with[v]=i;
                minn[v]=min(minn[u],edge[i]);
                if(!vis[v]) { vis[v]=1; q.push(v); }
            }
        }
    }
    return dis[T]!=0x3f3f3f3f3f3f3f3fLL;
}
int f(int x)//反向弧 
{
    if(x%2) return x+1;
    else return x-1;
}
int find_way()//寻找增广路 
{
    for(int i=T;i!=S;i=ver[f(with[i])])
    {
        edge[with[i]]-=minn[T];
        edge[f(with[i])]+=minn[T];
    }
    return minn[T]*dis[T];
}
long long solve()
{
    long long temp,ret=0;
    while(Spfa())
    {
        temp=find_way();
        ret+=temp;
    }
    return ret;
}
int main()
{
    scanf("%d%d",&n,&m);S=n+m+10,T=S+1;
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&s[i],&e[i],&c[i]);
        add(e[i]+1,s[i],0x7f7f7f7f,c[i]);
    }
    for(int i=2;i<=n+1;i++) add(i-1,i,0x7f7f7f7f,0);
    for(int i=1;i<=n+1;i++)
    {
        int temp=a[i]-a[i-1];
        if(temp>=0) add(i,T,temp,0);
        else add(S,i,-temp,0);
    }
    for(int i=1;i<=m;i++) add(nag[i],pos[i],0x7f7f7f7f,c[i]);
    printf("%lld\n",solve());
    return 0;
}
posted @ 2017-01-10 16:23  Czarina  阅读(199)  评论(0编辑  收藏  举报