hdu4307 Matrix

如果 ai=1 ,那么 B 的第i行的和就会被加入到结果中,同时,也会减去 Ci 的值。
如果 ai=0 ,那么什么都不会发生。
如果 ai=0 aj=1 ,那么之前的 B 的第j的行的和会多算了 Bji
将包含源点的集合作为 ai=0 的集合,将包含汇点的集合作为 ai=1 的集合,按照上述关系建图求最小割即可(需要转换一下关系)。
因为边数比较大,用sap需要开一下gap外挂。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<climits>
#include<cstdio>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
typedef long long ll;
const int up=INT_MAX;
struct eg{
    int u,v,nx,c;
}gp[5000010];
int cnt,hd[3010],sn;
void _psh(int u,int v,int c){
    ++cnt;
    gp[cnt].u=u,gp[cnt].v=v,gp[cnt].c=c;
    gp[cnt].nx=hd[u],hd[u]=cnt;
};
inline void psh(int u,int v,int c){
    _psh(u,v,c);_psh(v,u,0);
};
int eg[3010],pi[3010],gap[3010],ds[3010];
int sap(){
    int r=0,i,t,ic=up,v=0;bool fg;
    clr(gap),clr(ds);
    for(i=0;i<=sn;++i)eg[i]=hd[i];
    while(ds[0]!=sn+1){
        if(v==sn){
            r+=ic;
            for(;v;v=gp[pi[v]].u){
                gp[pi[v]].c-=ic;
                gp[pi[v]&1?pi[v]+1:pi[v]-1].c+=ic;
            }
            ic=up;
        }
        for(fg=0,i=eg[v];i&&!fg;i=gp[i].nx){
            if(gp[i].c&&ds[gp[i].v]+1==ds[v]){
                fg=1;
                pi[gp[i].v]=i;
                eg[v]=i;
                ic=min(ic,gp[i].c);
                v=gp[i].v;
            }
        }
        if(fg)continue;
        --gap[ds[v]];
        if(gap[ds[v]]==0)ds[0]=sn+1;
        for(t=up,i=hd[v];i;i=gp[i].nx){
            if(gp[i].c&&ds[gp[i].v]!=sn+1)
                t=min(t,ds[gp[i].v]);
        }
        ds[v]=t<up?t+1:sn+1;
        gap[ds[v]]++;
        eg[v]=hd[v];
        v=v?gp[pi[v]].u:0;
    }
    return r;
};
int n;
int br[1010][1010],cr[1010];
int sr[1010];
void cl(){
    int i,j,k,sm;scanf("%d",&n);
    for(i=1,sm=0;i<=n;++i){
        sr[i]=0;
        for(j=1;j<=n;++j){
            scanf("%d",&br[i][j]);
            sr[i]+=br[i][j];
        }
        sm+=sr[i];
    }
    for(i=1;i<=n;++i)scanf("%d",&cr[i]);
    clr(hd),cnt=0,sn=n+1;
    for(i=1;i<=n;++i){
        psh(0,i,cr[i]);
        psh(i,sn,sr[i]);
        for(j=1;j<=n;++j){
            if(i!=j){
                psh(i,j,br[j][i]);
            }
        }
    }
    printf("%d\n",sm-sap());
};
int main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
#endif
    int t;scanf("%d",&t);
    while(t--)cl();
    return 0;
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值