[BZOJ3996] [TJOI2015]线性代数

题目要求

ans=Maximizei=1NA1,ij=1NA1,jBi,jC1,i

方法一
直接推到最小割
因为目标函数最大化,所以先将其转为最小化

sum=i=1Nj=1NBi,j

cost=i=1NA1,ij=1N(1A1,j)Bi,j+Ci+i=1N(1A1,i)j=1NBi,j


ans=totMinimize(cost)

方法二
最大权闭合子图
一个 Bi,j 被加入答案,那么 A1,i A1,j 必须都是 1 ,在图中可以看做点Bi,j被选的前提是 A1,i A1,j 被选
一个 C1,i 被答案减去, A1,i 必须是 1 ,在图中可以看做A1,i的点权.
于是我们得到了一个有向图,图中的每个 Bi,j 都由两个点 A1,i A1,j 指向.
每个 A 点的点权为 C1,i , 每个 B 点 的点权是Bi,j
然后裸最大权闭合子图辣

/****************************************\
* Author : ztx
* Title  : [bzoj] 3996 [TJOI2015]线性代数
* ALG    : 嘛,最小割大水题,但是把它想成最大权闭合子图就太高达上了QAQ
* CMT    : 
* Time   : 
\****************************************/

#include <cstdio>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
typedef long long ll ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
    if (CH == '-') NEG = true , CH = getchar() ;
    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
    if (NEG) ret = -ret ;
}
template <typename TP>inline void readc(TP& ret) {
    while (ret=getchar() , ret<'!') ;
    while (CH=getchar() , CH>'!') ;
}
template <typename TP>inline void reads(TP *ret) {
    ret[0]=0;while (CH=getchar() , CH<'!') ;
    while (ret[++ret[0]]=CH,CH=getchar(),CH>'!') ;
    ret[ret[0]+1]=0;
}

#define  maxN  300010LL
#define  maxM  900010LL
#define  infi  0x7f7f7f7fLL
#define  min(x,y) ((x)<(y)?(x):(y))

struct FST { int to,next,flow; } e[maxM<<1] ;
int star[maxN] = {0} , tote = 1 ;
inline void AddEdge(int u,int v,int cap) {
    e[++tote].to=v;e[tote].flow=cap;e[tote].next=star[u];star[u]=tote;
    e[++tote].to=u;e[tote].flow=0;e[tote].next=star[v];star[v]=tote;
}

int n , S , T , N ;
int h[maxN] = {0} , vh[maxN] = {0} ;

int dfs(int u,int flowu) {
int p , tmp = h[u]+1 ;
int flow = 0 , flowv ;
    if (u == T) return flowu ;
    for (p = star[u] ; p ; p = e[p].next)
        if (e[p].flow>0 && h[u]==h[e[p].to]+1) {
            flowv = dfs(e[p].to,min(e[p].flow,flowu-flow)) ;
            flow += flowv ; e[p].flow -= flowv , e[p^1].flow += flowv ;
            if (h[S]==N || flow==flowu) return flow ;
        }
    for (p=star[u] ; p ; p=e[p].next)
        if (e[p].flow>0 && h[e[p].to]<tmp) tmp = h[e[p].to] ;
    if (--vh[h[u]] == 0) h[S] = N ;
    else ++vh[h[u]=tmp+1] ;
    return flow ;
}

inline int SAP() {
    int ret = 0 ;
    vh[0] = N ;
    while (h[S] < N) ret += dfs(S,infi) ;
    return ret ;
}

inline int A(int i) { return n*n+i ; }
inline int B(int i,int j) { return (i-1)*n+j ; }

int main() {
int i , j , w , ans ;
    #define READ
    #ifdef  READ
        freopen("data.in" ,"r",stdin ) ;
        freopen("data.out","w",stdout) ;
    #endif
    read(n) ;
    S = n*n+n+1 , T = N = S+1 ;
    ans = 0 ;
    Rep (i,1,n) Rep (j,1,n) {
        read(w) ;
        ans += w ;
        AddEdge(B(i,j),T,w) ;
        AddEdge(A(i),B(i,j),infi) ;
        AddEdge(A(j),B(i,j),infi) ;
    }
    Rep (i,1,n) {
        read(w) ;
        AddEdge(S,A(i),w) ;
    }
    ans -= SAP() ;
    printf("%d\n", ans) ;
    #ifdef  READ
        fclose(stdin) ; fclose(stdout) ;
    #else
        getchar() ; getchar() ;
    #endif
    return 0 ;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值