zoukankan      html  css  js  c++  java
  • BZOJ3997: [TJOI2015]组合数学(网络流)

    3997: [TJOI2015]组合数学

    Time Limit: 20 Sec  Memory Limit: 128 MB
    Submit: 405  Solved: 284
    [Submit][Status][Discuss]

    Description

     给出一个网格图,其中某些格子有财宝,每次从左上角出发,只能向下或右走。问至少走多少次才能将财宝捡完。此对此问题变形,假设每个格子中有好多财宝,而每一次经过一个格子至多只能捡走一块财宝,至少走多少次才能把财宝全部捡完。

     

    Input

     第一行为正整数T,代表数据组数。

    每组数据第一行为正整数N,M代表网格图有N行M列,接下来N行每行M个非负整数,表示此格子中财宝数量,0代表没有

    Output

     输出一个整数,表示至少要走多少次。

     

    Sample Input

    1
    3 3
    0 1 5
    5 0 0
    1 0 0

    Sample Output

    10

    HINT

     N<=1000,M<=1000.每个格子中财宝数不超过10^6

    Source

    把公式写出来就是ni=1nj=1Bij×Ai×Ajni=1Ai×Ci

    于是可以看出是一个最大权闭合图,我要获得bij这个点的收益就要付出ci和cj的费用。

    经典的最小割。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #define rep(i,l,r) for(int i=l;i<=r;i++)
    #define clr(x,y) memset(x,y,sizeof(x));
    #define maxn 505
    #define maxm 505500
    #define inf int(1e9)
    using namespace std;
    struct data{int obj;int pre;int c;
    }e[3005000];
    int head[maxm],b[maxn][maxn],c[maxn],uu[maxm],s,t,n,sum,tot=1,q[3005000];
    void insert(int x,int y,int z){
    e[++tot].obj=y; e[tot].c=z; e[tot].pre=head[x]; head[x]=tot;
    e[++tot].obj=x; e[tot].c=0; e[tot].pre=head[y]; head[y]=tot;
    }
    bool bfs(){
    clr(uu,-1);
    int l=0,r=1; q[1]=s; uu[s]=0;
    while (l<r){
    int u=q[++l];
    for(int j=head[u];j;j=e[j].pre){
    int v=e[j].obj;
    if (uu[v]==-1&&e[j].c>0) {
    q[++r]=v; uu[v]=uu[u]+1;
    }
    }
    }
    if (uu[t]<0) return 0;
    return 1;
    }
    int dfs(int u,int mx){
    int used=0,w;
    if (u==t||mx==0) return mx;
    for(int j=head[u];j;j=e[j].pre){
    int v=e[j].obj;
    if (uu[v]==uu[u]+1&&e[j].c>0){
    w=dfs(v,min(mx-used,e[j].c));
    if (w<=0) {uu[v]=-1; continue;}
    e[j].c-=w; e[j^1].c+=w; used+=w;
    if (used==mx) return used;
    }
    }
    return used;
    }
    int dinic(){
    int ans=0;
    while (bfs())
    ans+=dfs(s,inf);
    return ans;
    }
    int main(){
    scanf("%d",&n);
    s=0; t=n+n*n+1;
    rep(i,1,n)
    rep(j,1,n)
    scanf("%d",&b[i][j]),sum+=b[i][j];
    rep(i,1,n) scanf("%d",&c[i]),insert(n*n+i,t,c[i]);
    rep(i,1,n){
    rep(j,1,n){
    insert(s,(i-1)*n+j,b[i][j]);
    insert((i-1)*n+j,n*n+i,inf);
    insert((i-1)*n+j,n*n+j,inf);
    }
    }
    printf("%d ",sum-dinic());
    return 0;
    }

  • 相关阅读:
    caffe杂
    easyui 扩展layout的方法,支持动态添加删除块
    easyui换主题,并记录在cookie
    $.messager.show扩展:指定位置显示
    easyui 扩展 之 Tree的simpleData加载
    easyui menu 添加hideItem/showItem 方法
    HTML标签及属性大全
    适应各种内核浏览器的透明修过样式
    让IE6支持min-width和max-width的方法
    javascript获取html标记的的绝对定位值
  • 原文地址:https://www.cnblogs.com/ctlchild/p/4661510.html
Copyright © 2011-2022 走看看