【费用流】[BZOJ1061]/[HYSBZ1061]志愿者招募

来源:互联网 发布:淘宝买lol账号流程 编辑:程序博客网 时间:2024/05/25 08:15

题目
分析:建图的方法还是比较难想。
首先,计算两个相邻时刻的差分,若a[i] < a[i-1],就从i向汇点连边,容量为a[i-1]-a[i],若a[i] > a[i-1],就从源点向i连边,容量为a[i]-a[i-1]
请联系差分数组理解。
然后,对于志愿者,连s->(t+1),容量为+∞,费用为c。
最后,由于志愿者可以多不能少,连(i+1)->i,容量为+∞。
跑费用流算出费用即可。

#include<cstdio>#include<algorithm>#include<cstring>#include<queue>#define MAXN 1000#define MAXM 10000#define INF 0x7f7f7f7f7f7f7f7fllusing namespace std;deque<int>q;void Read(int &x){    char c;    while(c=getchar(),c!=EOF)        if(c>='0'&&c<='9'){            x=c-'0';            while(c=getchar(),c>='0'&&c<='9')                x=x*10+c-'0';            ungetc(c,stdin);            return;        }}int n,m,S,T,a[MAXN+10];typedef long long LL;LL dist[MAXN+10],cost;bool vis[MAXN+10];struct node{    int wt,v;    LL cap;    node *next,*back;}*adj[MAXN+10],edge[MAXN*4+MAXM*2+10],*ecnt=edge,*pre[MAXN+10];template<class T>void Read(T &x){    char c;    while(c=getchar(),c!=EOF)        if(c>='0'&&c<='9'){            x=c-'0';            while(c=getchar(),c>='0'&&c<='9')                x=x*10+c-'0';            ungetc(c,stdin);            return;        }}void addedge(int u,int v,int wt,LL cap){    node *p=++ecnt;    p->v=v;    p->wt=wt;    p->cap=cap;    p->next=adj[u];    adj[u]=p;    p=p->back=++ecnt;    p->v=u;    p->wt=-wt;    p->cap=0;    p->next=adj[v];    adj[v]=p;    p->back=ecnt-1;}void read(){    Read(n),Read(m);    int i,s,t,c;    T=n+2;    for(i=1;i<=n;i++)        Read(a[i]);    for(i=1;i<=n;i++){        if(a[i]>a[i-1])            addedge(S,i,0,a[i]-a[i-1]);        else if(a[i]<a[i-1])            addedge(i,T,0,a[i-1]-a[i]);        addedge(i+1,i,0,INF);    }    addedge(n+1,T,0,a[n]);    for(i=1;i<=m;i++){        Read(s),Read(t),Read(c);        addedge(s,t+1,c,INF);    }}bool spfa(){    memset(dist,0x7f,sizeof dist);    memset(pre,0,sizeof pre);    q.push_back(S);    vis[S]=1;    dist[S]=0;    int u,v,len;    LL sum;    while(!q.empty()){        u=q.front();        q.pop_front();        if(dist[u]*len>sum){            q.push_back(u);            continue;        }        len--;        sum-=dist[u];        vis[u]=0;        for(node *p=adj[u];p;p=p->next){            v=p->v;            if(p->cap>0&&dist[v]>dist[u]+p->wt){                dist[v]=dist[u]+p->wt;                pre[v]=p;                if(!vis[v]){                    vis[v]=1;                    if(q.empty()||dist[v]>dist[q.front()])                        q.push_back(v);                    else                        q.push_front(v);                    sum+=dist[v];                    len++;                }            }        }    }    if(dist[T]==INF)        return 0;    return 1;}void mcmf(){    int u;    LL delta;    while(spfa()){        delta=INF;        for(u=T;u!=S;u=pre[u]->back->v)            delta=min(delta,pre[u]->cap);        for(u=T;u!=S;u=pre[u]->back->v){            pre[u]->cap-=delta;            pre[u]->back->cap+=delta;            cost+=delta*pre[u]->wt;        }    }}int main(){    read();    mcmf();    printf("%lld\n",cost);}
0 0
原创粉丝点击