bzoj 2039 [2009国家集训队]employ人员雇佣——二元关系

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2039

用最小割看。对于一组关系 i , j ,如果都选,收益 2*Ei,j,可以看作0,作为基准;如果一个选了一个没选,不仅没了 2*Ei,j,还会额外少E,所以是3*E;如果两个都没选,就是少了E;解一下的话, i 和 j 相互连边的容量是 2*E ;源点连来的容量是0,连向汇点的容量是E。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1005,M=N*N<<1;
const ll INF=3e12;
int n,hd[N],xnt=1,cur[N],dfn[N];ll f[N];
int to[M],nxt[M];ll cap[M];
int q[N],he,tl;
ll Mn(ll a,ll b){return a<b?a:b;}
int rdn()
{
  int ret=0;bool fx=1;char ch=getchar();
  while(ch>'9'||ch<'0'){if(ch=='-')fx=0;ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return fx?ret:-ret;
}
void add(int x,int y,ll z)
{
  to[++xnt]=y;nxt[xnt]=hd[x];hd[x]=xnt;cap[xnt]=z;
  to[++xnt]=x;nxt[xnt]=hd[y];hd[y]=xnt;cap[xnt]=0;
}
bool bfs()
{
  memset(dfn,0,sizeof dfn);dfn[0]=1;
  q[he=tl=1]=0;
  while(he<=tl)
    {
      int k=q[he++];
      for(int i=hd[k],v;i;i=nxt[i])
    if(!dfn[v=to[i]]&&cap[i])
      dfn[v]=dfn[k]+1,q[++tl]=v;
    }
  return dfn[n+1];
}
ll dinic(int cr,ll flow)
{
  if(cr==n+1)return flow;
  ll use=0;
  for(int& i=cur[cr],v;i;i=nxt[i])
    if(dfn[v=to[i]]==dfn[cr]+1&&cap[i])
      {
    ll tmp=dinic(v,Mn(flow-use,cap[i]));
    if(!tmp)dfn[v]=0;
    use+=tmp;cap[i]-=tmp;cap[i^1]+=tmp;
    if(use==flow)return use;
      }
  return use;
}
int main()
{
  n=rdn();
  for(int i=1,d;i<=n;i++)
    d=rdn(),add(0,i,d);
  for(int i=1,d;i<=n;i++)
    for(int j=1;j<=n;j++)
      {
    d=rdn();if(i==j)continue;
    add(i,j,(ll)d<<1ll);f[i]+=d;
      }
  ll ans=0;
  for(int i=1;i<=n;i++)add(i,n+1,f[i]),ans+=f[i];
  while(bfs())memcpy(cur,hd,sizeof hd),ans-=dinic(0,INF);
  printf("%lld\n",ans);
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/Narh/p/10121088.html
今日推荐