bzoj 2039 & 洛谷 P1791 人员雇佣 —— 二元关系最小割

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

https://www.luogu.org/problemnew/show/P1791

做法就这样:https://www.cnblogs.com/BearChild/p/6426850.html

如果不是先连边再加边权(话说这样很奇怪啊),而是算好边权再连边,再各种等价改一改,就能快2000ms,能在洛谷上A了...

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
typedef long long ll;
int const xn=1005,xm=5e6+5;
int n,hd[xn],cur[xn],ct=1,to[xm],nxt[xm],dis[xn],S,T;
ll c[xm],inf=1e17;
queue<int>q;
ll rd()
{
  ll ret=0,f=1; char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
  while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
  return f?ret:-ret;
}
void ade(int x,int y,ll f){to[++ct]=y; nxt[ct]=hd[x]; hd[x]=ct; c[ct]=f;}
void add(int x,int y,ll f){ade(x,y,f); ade(y,x,0);}
bool bfs()
{
  memset(dis,0,sizeof dis);
  dis[S]=1; q.push(S);
  while(q.size())
    {
      int x=q.front(); q.pop();
      for(int i=hd[x],u;i;i=nxt[i])
    if(!dis[u=to[i]]&&c[i])dis[u]=dis[x]+1,q.push(u);
    }
  return dis[T];
}
ll dfs(int x,ll fl)
{
  if(x==T)return fl;
  ll ret=0;
  for(int &i=cur[x],u;i;i=nxt[i])
    {
      if(dis[u=to[i]]!=dis[x]+1||!c[i])continue;
      ll tmp=dfs(u,min(fl-ret,c[i]));
      if(!tmp)dis[u]=0;
      c[i]-=tmp; c[i^1]+=tmp;
      ret+=tmp; if(ret==fl)break;
    }
  return ret;
}
int main()
{
  n=rd(); ll x,ans=0; S=0; T=n+1;
  for(int i=1;i<=n;i++)x=rd(),add(S,i,x);
  for(int i=1;i<=n;i++)
    {
      ll sum=0;
      for(int j=1;j<=n;j++)
    {
      x=rd(); add(i,j,x<<1ll);
      sum+=x;
      }
      add(i,T,sum); ans+=sum;
    }
  while(bfs())
    {
      memcpy(cur,hd,sizeof hd);
      ans-=dfs(S,inf);
    }
  printf("%lld\n",ans);
  return 0;
}

 

posted @ 2018-12-14 19:18  Zinn  阅读(182)  评论(0编辑  收藏  举报