题解 P1791 【[国家集训队]人员雇佣】

Freopen

2019-03-12 18:56:03

Solution

(我是不会告诉你们,在连边的时候判一下是不是0,是就不连边,就可以rank1。。。。。。) 这题就是一个网络流最小割在二元关系下求最大值的题。 先把矩阵中所有数加起来再减去我们构造的最小割就是最大值。 而最小割。 我们把每个人和S和T连边,割与S相连的边表示聘用,否则表示不聘用。那么一开始每个点与S相连的边的边权为b。 然后来考虑二元关系; 对于i,j,同时选的代价是0(我们一开始就加入了贡献)。 同时不选的代价是$E_{ij}+E{ji}$ 一个选一个不选的代价是$E_{ij}+E{ji}+E{ij}$(需要减去一开始加的E) 通过(和其他二元关系一样的)解方程,我们可以得到i,j与S的连边流量为0,与T的连边流量为$E_{ij}$,i,j之间的连边流量为$2*E_{ij}$ 然后再把b加上去就行了。 AC Code(20190312 Rank1 72ms): ```cpp #include<bits/stdc++.h> #define maxn 1055 #define maxm maxn * maxn * 5 #define inf 0x3f3f3f3f #define LL long long using namespace std; char cb[1<<15],*cs=cb,*ct=cb; #define getc() (cs==ct && (ct = (cs = cb) + fread(cb , 1 , 1<<15 , stdin),cs==ct)?0:*cs++) void read(int &res) { char ch;bool f=0; for(;!isdigit(ch=getc());) if(ch=='-') f=1; for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0'); (f) && (res = -res); } int n,S,T,tot; int b[maxn]; LL sum[maxn],cap[maxm]; int dis[maxn]; int buf[maxn],info[maxn],Prev[maxm],to[maxm],cnt_e=1; inline void Node(int u,int v,LL c){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v,cap[cnt_e]=c; } inline void Line(int u,int v,LL c,LL d=0){ Node(u,v,c),Node(v,u,d); } LL aug(int now,LL Max) { if(now == T) return Max; LL inc , st = Max; for(int &i=info[now];i;i=Prev[i]) if(cap[i] && dis[to[i]]+1 == dis[now]) { inc = aug(to[i],min(cap[i] , st)); if(inc) st -= inc , cap[i] -= inc , cap[i^1] += inc; else dis[to[i]] = 0; if(!st) break; } return Max - st; } bool BFS() { static queue<int>q; memset(dis,-1,sizeof dis); q.push(T),dis[T]=0; for(int now;!q.empty();) { now = q.front() , q.pop(); for(int i=info[now];i;i=Prev[i]) if(cap[i^1] && dis[to[i]]==-1) { dis[to[i]] = dis[now] + 1; q.push(to[i]); } } return dis[S] != -1; } int main() { read(n); tot = n; S = ++tot , T = ++tot; LL ans = 0; for(int i=1;i<=n;i++) read(b[i]); for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { int x; read(x); if(i<j && x) { ans += x*2; sum[i] += x, sum[j] += x; Line(i,j,x*2ll,x*2ll); } } for(int i=1;i<=n;i++) Line(S,i,b[i]),Line(i,T,sum[i]); memcpy(buf,info,sizeof info); for(;BFS();) ans -= aug(S,inf), memcpy(info,buf,sizeof buf); printf("%lld\n",ans); } ```