bzoj1497 [NOI2006]最大收益

来源:互联网 发布:剑三画面优化 编辑:程序博客网 时间:2024/05/04 11:34

最小割 思路比较简单
点数看起来很多但是因为是类似二分图的东西所以跑的比较快
源点对每个用户连容量为收益的边 用户向中转站连容量无穷大的边 中转站向汇点连容量为成本的边
要么割掉用户带来的收益 要么割掉成本

#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int N=60005,M=N*6,S=N-1,T=N-2,INF=1e9;int n=0,m=0;int head[N],to[M],c[M],f[M],next[M],edge=0;int ans=0;int q[M],front=0,back=0,d[N],cur[N];inline void addEdge(int u,int v,int ac) {    c[edge]=ac,to[edge]=v,next[edge]=head[u],head[u]=edge++;    c[edge]=0,to[edge]=u,next[edge]=head[v],head[v]=edge++;}inline void build() {    memset(head,-1,sizeof(head));    for (int i=1;i<=n;++i) {        int p=0;        scanf("%d",&p);        addEdge(m+i,T,p);    }    for (int i=1;i<=m;++i) {        int a=0,b=0,c2=0;        scanf("%d %d %d",&a,&b,&c2);        ans+=c2;        addEdge(S,i,c2);        addEdge(i,m+a,INF);        addEdge(i,m+b,INF);    }}inline int bfs() {    front=back=0;    memset(d,-1,sizeof(d));    d[S]=1;    q[back++]=S;    while (front<back) {        int x=q[front++];        for (int e=head[x];~e;e=next[e]) {            int v=to[e];            if (d[v]==-1 && c[e]>f[e]) {                d[v]=d[x]+1;                q[back++]=v;            }        }    }       return d[T]!=-1;}inline int dfs(int x,int t) {    if (x==T || !t)        return t;    int flow=0;    for (int e=cur[x];~e;e=next[e]) {        int v=to[e];        if (d[v]==d[x]+1 && c[e]>f[e]) {            int f0=dfs(v,min(t,c[e]-f[e]));            flow+=f0;            t-=f0;            f[e]+=f0;            f[e^1]-=f0;            if (c[e]>f[e])                cur[x]=e;            if (!t)                return flow;        }    }    if (t)        d[x]=-1;    return flow;}inline void dinic() {    while (bfs()) {        for (int e=1;e<=S;++e)            cur[e]=head[e];        ans-=dfs(S,INF);    }}int main(void) {    scanf("%d %d",&n,&m);    build();    dinic();    printf("%d\n",ans);         return 0;} 
0 0
原创粉丝点击