2039: [2009国家集训队]employ人员雇佣

来源:互联网 发布:电解质溶液的电导数据 编辑:程序博客网 时间:2024/06/15 03:17

题目链接

题目大意:给定n个人,每个人有一个佣金,i和j如果同时被雇佣会产生2*E(i,j)的效益,i和j如果一个被雇佣一个不被雇佣会产生E(i,j)的亏损,求最大收益

题解:转化成最小割,和S相连表示不选,和T相连表示选取,割表示损失的部分

对于雇佣的人i和T相连,就要和S割断,所以S向i连容量为雇佣费用的边
对于雇佣的人i和S相连,就要和T割断,损失E[i][j]T

对于一对点i,j,连边(i,j,2*E[i][j]),表示如果不选i,选了j的话,本来i中选j的利益得不到,又要损失j对i的影响为E[i][j],一共损失了2*E[i][j]

任意点i到T连一条容量为Σ(j=1,n)E[i,j]的边
任意两点i,j间连一条容量为2*E[i,j]的双向边
任意点i到S连一条边,容量为雇佣的费用

再次Orz神奇题解

我的收获:

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int M=1005;#define INF 1e15int n,m,st,ed,t;int head[M],last[M],d[M],num[M];long long sum;bool Exit;struct edge{int to,nex;long long c;}e[M*M*2];void add(int u,int v,long long w){e[t].to=v,e[t].nex=head[u],e[t].c=w,last[u]=head[u]=t++;}void insert(int x,int y,long long z){add(x,y,z),add(y,x,0);};long long dfs(int x,long long in){    if(x==ed) return in;    long long ans=0,f;    for(int i=last[x];i!=-1;last[x]=i=e[i].nex)    {        int v=e[i].to;        if(e[i].c&&d[v]==d[x]-1){            f=dfs(v,min(in-ans,e[i].c));            ans+=f;e[i].c-=f,e[i^1].c+=f;            if(Exit||ans==in) return ans;        }    }    if(--num[d[x]]==0) Exit=1;    d[x]++,num[d[x]]++,last[x]=head[x];    return ans;}long long ISAP(){    Exit=0;long long flow=0;    while(!Exit) flow+=dfs(st,INF);    return flow;}void work(){    cout<<sum-ISAP()<<endl;} void init(){    cin>>n;    st=0,ed=n+1,num[0]=ed+1;    memset(head,-1,sizeof(head));    memset(last,-1,sizeof(last));    long long x,resi;    for(int i=1;i<=n;i++)        scanf("%lld",&x),insert(st,i,x);    for(int i=1;i<=n;i++){        resi=0;        for(int j=1;j<=n;j++)        {            scanf("%lld",&x);            sum+=x,resi+=x;            insert(i,j,x<<1);        }        insert(i,ed,resi);    } }int main(){    init();    work();    return 0;}
阅读全文
0 0
原创粉丝点击