bzoj 2039 人员雇佣【最小割】

来源:互联网 发布:打死不看右下角软件 编辑:程序博客网 时间:2024/05/22 04:54

题目大意:n 个人,每个人选择的代价为 cost,若两个人 i,j 同时选中则有贡献 E[i,j] 否则只有一个人被选则有 E[i,j] 的代价,求最大收益

做不来…orz
建图:
·S -> i nk=1E[
·i <-> j 2E[i,j]
·i -> T cost[i]

#include<iostream>#include<cstring>#include<cstdio>#define N 1005#define M 1010005#define INF 1000000000000000ll#define LL long longusing namespace std;int n,m,siz = 1,S,T,x;LL ans,w[N],len[M];int first[N],next[M],to[M];int d[N],p[N];bool v[N];void inser(int x,int y,LL w){    next[++ siz] = first[x];    first[x] = siz;    to[siz] = y;    len[siz] = w;}void add_edge(int x,int y,LL w){    inser(x,y,w),inser(y,x,0);}bool bfs(){    int head = 0,tail = 1;    memset(d,0,sizeof(d));    d[p[1] = S] = 1;    while (head ^ tail)    {        int x = p[++ head];        for (int i = first[x];i;i = next[i])            if (len[i] && !d[to[i]]) d[p[++ tail] = to[i]] = d[x] + 1;    }    return d[T];}int dfs(int x,LL flow){    if (x == T) return flow;    LL ret = 0;    for (int i = first[x];i && flow;i = next[i])        if (d[to[i]] == d[x] + 1 && len[i])        {            int w = dfs(to[i],min(len[i],flow));            len[i] -= w,len[i ^ 1] += w;            flow -= w,ret += w;        }    if (!ret) d[x] = 0;    return ret;}int dinic(){    int ret = 0;    while (bfs()) ret += dfs(S,INF);    return ret;}int main(){    scanf("%d",&n),S = n+1,T = S+1;    for (int i = 1;i <= n;i ++)        scanf("%d",&x),add_edge(i,T,x);    for (int i = 1;i <= n;i ++)        for (int j = 1;j <= n;j ++)        {            scanf("%d",&x),ans += x;            if (i >= j) continue;            w[i] += x,w[j] += x;            inser(i,j,(LL)x << 1);            inser(j,i,(LL)x << 1);        }    for (int i = 1;i <= n;i ++) add_edge(S,i,w[i]);    cout << ans - dinic() << endl;    return 0;}
0 0