zoukankan      html  css  js  c++  java
  • 【HNOI】d 最小割

      【题目大意】给定一个n*m的土地,每块可以种a或b作物,每种作物在不同的位置有不同的收成,同时,有q个子矩阵中,全部种指定的作物(a或b)会有一定的加成收成,求最大收成。  

      【数据范围】

        50% n,m<=10 q<=500

        100% n,m<=100 q<=50000

      首先我们解决小范围数据,比较容易的可以看出来这是一个最小割模型,先将ans+=value。我们只需要(source,i,value[i][0]),表示不种植a的代价,(i,sink,value[i][1])表示不种植b的代价。对于额外的加成,如果全是b作物,我们可以表示为(x,cur,inf),(cur,sink,value) x为矩阵中的所有点,这个表示我们只要矩阵中的任意一个元素没有种植b(也就是某个点割得与sink相连的边),那么我们都可以找到一条新的增广路,流量为value。

      那么我们可以发现,这种建模的边是n*m*q级别的,因为每次我们新的cur点都与矩阵中所有的点连接了,我们需要来增加图的点的数量来减少边的数量,那么我们可以用二维st表来表示每个矩阵中的点,num[i][j][p][q]表示矩阵中i,j点为左上角,长为2^p,宽为2^q的矩阵,我们将图拆为a,b两层,分别表示a,b作物的矩阵。

      因为新加入的点是为了简化之前的图的,所以我们同层的st表之间的边应该与之前连接的边的方向相同,因为我们这样做相当与把原图拆成了两部分,原图的两部分之间是互通的,所以我们也应该将两层st表之间加上双向边,如果不加这个的话,会出现由于额外价值过大导致割了连接源和汇的边而保留两个附加收成的点,这样当然是不合法的。

      反思:开始建的是正方形的st表,后来发现了这种建发的诸多不便,这样不能保证图的规模,因为条形的矩阵可以卡掉这个。然后开始的图没有两层之间双向连边,所以导致了些奇奇怪怪的问题(也不奇怪,就是上述的不合法割边)。

    //By BLADEVIL
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define maxm 2000010
    #define maxn 110
    #define inf (1000000000)
    
    using namespace std;
    
    int n,m,query;
    int source,sink,tot,l;
    int key[maxn][maxn][3],num[maxn][maxn][10][10][3];
    int pre[maxm],other[maxm],last[maxm],len[maxm];
    int que[maxm],dis[maxm];
    
    void connect(int x,int y,int z) {
        pre[++l]=last[x];
        last[x]=l;
        other[l]=y;
        len[l]=z;
        //printf("|%d %d %d
    ",x,y,z);
    }
    
    bool bfs() {
        memset(dis,0,sizeof dis);
        que[1]=source; dis[source]=1;
        int h=0,t=1;
        while (h<t) {
            int cur=que[++h];
            for (int p=last[cur];p;p=pre[p]) {
                if (len[p]<=0) continue;
                if (!dis[other[p]]) {
                    que[++t]=other[p];
                    dis[other[p]]=dis[cur]+1;
                    if (other[p]==sink) return true;
                }
            }
        }
        return false;
    }
    
    int dinic(int x,int flow) {
        //printf("%d %d
    ",x,flow);
        if (x==sink) return flow;
        int rest=flow;
        for (int p=last[x];p;p=pre[p]) {
            if (len[p]<=0) continue;
            if (!rest) continue;
            if (dis[other[p]]!=dis[x]+1) continue;
            int tmp=dinic(other[p],min(rest,len[p]));
            len[p]-=tmp; len[p^1]+=tmp; rest-=tmp;
        }
        return flow-rest;
    }
    
    int main() {
        freopen("d.in","r",stdin); freopen("d.out","w",stdout);
        scanf("%d%d%d",&n,&m,&query);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++) scanf("%d",&key[i][j][0]);
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++) scanf("%d",&key[i][j][1]);
        l=1;
        for (int p=0;(1<<p)<=n;p++)    
            for (int q=0;(1<<q)<=m;q++) 
                for (int i=1;i+(1<<p)-1<=n;i++)
                    for (int j=1;j+(1<<q)-1<=m;j++) {
                        num[i][j][p][q][0]=++tot; num[i][j][p][q][1]=++tot;
                    }
        source=++tot; sink=++tot;
        int ans=0;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++) {
                connect(source,num[i][j][0][0][1],key[i][j][1]); connect(num[i][j][0][0][1],source,0);
                connect(num[i][j][0][0][0],sink,key[i][j][0]); connect(sink,num[i][j][0][0][0],0);
                ans+=key[i][j][0]+key[i][j][1];
            }
        for (int i=1;i<=n;i++)
            for (int j=1;j<=m;j++)
                connect(num[i][j][0][0][1],num[i][j][0][0][0],inf),connect(num[i][j][0][0][0],num[i][j][0][0][1],0);
        for (int p=0;(1<<p)<=n;p++)
            for (int q=0;(1<<q)<=m;q++)
                for (int i=1;i+(1<<p)-1<=n;i++)
                    for (int j=1;j+(1<<q)-1<=m;j++) {
                        connect(num[i][j][p][q][0],num[i][j][p][q][1],inf);connect(num[i][j][p][q][1],num[i][j][p][q][0],0);
                        if (q) {
                            connect(num[i][j][p][q][0],num[i][j][p][q-1][0],inf); connect(num[i][j][p][q-1][0],num[i][j][p][q][0],0);
                            connect(num[i][j][p][q][0],num[i][j+(1<<(q-1))][p][q-1][0],inf); connect(num[i][j+(1<<(q-1))][p][q-1][0],num[i][j][p][q][0],0);
                            connect(num[i][j][p][q-1][1],num[i][j][p][q][1],inf); connect(num[i][j][p][q][1],num[i][j][p][q-1][1],0);
                            connect(num[i][j+(1<<(q-1))][p][q-1][1],num[i][j][p][q][1],inf); connect(num[i][j][p][q][1],num[i][j+(1<<(q-1))][p][q-1][1],0);
                        } else 
                        if (p) {
                            connect(num[i][j][p][q][0],num[i][j][p-1][q][0],inf); connect(num[i][j][p-1][q][0],num[i][j][p][q][0],0);
                            connect(num[i][j][p][q][0],num[i+(1<<(p-1))][j][p-1][q][0],inf); connect(num[i+(1<<(p-1))][j][p-1][q][0],num[i][j][p][q][0],0);
                            connect(num[i][j][p-1][q][1],num[i][j][p][q][1],inf); connect(num[i][j][p][q][1],num[i][j][p-1][q][1],0);
                            connect(num[i+(1<<(p-1))][j][p-1][q][1],num[i][j][p][q][1],inf);
                            connect(num[i][j][p][q][1],num[i+(1<<(p-1))][j][p-1][q][1],0);
                        }
                    }
        while (query--) {
            int x1,y1,x2,y2,w,z,q=0,p=0,cur=++tot; scanf("%d%d%d%d%d%d",&x1,&y1,&x2,&y2,&z,&w);
            ans+=w;
            while ((1<<(p+1))<=x2-x1+1) p++;
            while ((1<<(q+1))<=y2-y1+1) q++; 
            if (z) {
                connect(cur,sink,w); connect(sink,cur,0);
                connect(num[x1][y1][p][q][1],cur,inf); connect(cur,num[x1][y1][p][q][1],0);
                connect(num[x1][y2-(1<<q)+1][p][q][1],cur,inf); connect(cur,num[x1][y2-(1<<q)+1][p][q][1],0);
                connect(num[x2-(1<<p)+1][y1][p][q][1],cur,inf); connect(cur,num[x2-(1<<p)+1][y1][p][q][1],0);
                connect(num[x2-(1<<p)+1][y2-(1<<q)+1][p][q][1],cur,inf); connect(cur,num[x2-(1<<p)+1][y2-(1<<q)+1][p][q][1],0);
            } else {
                connect(source,cur,w); connect(cur,source,0);
                connect(cur,num[x1][y1][p][q][0],inf); connect(num[x1][y1][p][q][0],cur,0);
                connect(cur,num[x1][y2-(1<<q)+1][p][q][0],inf); connect(num[x1][y2-(1<<q)+1][p][q][0],cur,0);
                connect(cur,num[x2-(1<<p)+1][y1][p][q][0],inf); connect(num[x2-(1<<p)+1][y1][p][q][0],cur,0);
                connect(cur,num[x2-(1<<p)+1][y2-(1<<q)+1][p][q][0],inf); connect(num[x2-(1<<p)+1][y2-(1<<q)+1][p][q][0],cur,0);
            }
        }
        while (bfs()) ans-=dinic(source,inf);
        printf("%d
    ",ans);
        fclose(stdin); fclose(stdout);
        return 0;
    }
  • 相关阅读:
    字典相关函数(增删改查)
    列表的相关函数 (增删改查)
    【转】一个java页游服务器框架
    【转】CodeIgniter定义自己的Helper和Helper的方法
    【转】CodeIgniter配置之database
    【转】最简单的CI框架入门示例--数据库取数据
    ORACLE创建表空间、创建用户、更改用户默认表空间以及授权、查看权限(修改表空间大小)
    ORACLE创建表空间、创建用户、更改用户默认表空间以及授权、查看权限(修改表空间大小)
    学习oracle经常要光顾的几个网站整理
    学习oracle经常要光顾的几个网站整理
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3649890.html
Copyright © 2011-2022 走看看