您的位置:首页 > 其它

[bzoj] 3996 [TJOI2015]线性代数

2015-06-04 19:35 309 查看
题目要求

ans=Maximize∑i=1NA1,i⋅⎛⎝∑j=1NA1,j⋅Bi,j−C1,i⎞⎠ans = Maximize\quad\sum_{i=1}^{N} A_{1,i}\cdot\left(\sum_{j=1}^{N}A_{1,j}\cdot B_{i,j}-C_{1,i}\right)

方法一

直接推到最小割

因为目标函数最大化,所以先将其转为最小化



sum=∑i=1N∑j=1NBi,jsum=\sum_{i=1}^{N}\sum_{j=1}^{N}B_{i,j}

cost=∑i=1NA1,i⋅⎛⎝∑j=1N(1−A1,j)⋅Bi,j+Ci⎞⎠+∑i=1N(1−A1,i)⋅∑j=1NBi,jcost =\sum_{i=1}^{N}A_{1,i}\cdot\left(\sum_{j=1}^{N}\left(1-A_{1,j}\right)\cdot B_{i,j}+C_{i}\right)+\sum_{i=1}^{N}\left(1-A_{1,i}\right)\cdot\sum_{j=1}^{N}B_{i,j}



ans=tot−Minimize(cost)ans = tot-Minimize\left(cost\right)

方法二

最大权闭合子图

一个Bi,jB_{i,j}被加入答案,那么A1,iA_{1,i}与A1,jA_{1,j}必须都是11,在图中可以看做点Bi,jB_{i,j}被选的前提是A1,iA_{1,i}与A1,jA_{1,j}被选

一个C1,iC_{1,i}被答案减去,A1,iA_{1,i}必须是11,在图中可以看做A1,iA_{1,i}的点权.

于是我们得到了一个有向图,图中的每个Bi,jB_{i,j}都由两个点A1,iA_{1,i}与A1,jA_{1,j}指向.

每个AA点的点权为 −C1,i-C_{1,i} , 每个BB点 的点权是Bi,jB_{i,j}

然后裸最大权闭合子图辣

[code]/****************************************\
* 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 ;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: