zoukankan      html  css  js  c++  java
  • [GDKOI2010] 圈地计划(网络流)

    题2链接https://www.luogu.org/problemnew/show/P1935

    Description

    最近房地产商GDOI(Group of Dumbbells Or Idiots)从NOI(Nuts Old Idiots)手中得到了一块开发土地。据了解,这块土地是一块矩形的区域,可以纵横划分为N×M块小区域。GDOI要求将这些区域分为商业区和工业区来开发。根据不同的地形环境,每块小区域建造商业区和工业区能取得不同的经济价值。更具体点,对于第i行第j列的区域,建造商业区将得到Aij收益,建造工业区将得到Bij收益。

    题1 
    另外同种的区域连在一起可以得到额外的收益,即如果相邻有K块(显然K不超过4)同种类型的区域,则这块区域能增加k×Cij收益。

    上面注意是相同的区域可获得收益,而下面的是不同的区域可获得收益

    题2 
    另外不同的区域连在一起可以得到额外的收益,即如果区域(I,j)相邻(相邻是指两个格子有公共边)有K块(显然K不超过4)类型不同于(I,j)的区域,则这块区域能增加k×Cij收益。

    经过Tiger.S教授的勘察,收益矩阵A,B,C都已经知道了。你能帮GDOI求出一个收益最大的方案么?

    我们首先看T1

    仔细看题,对于每一块区域我们要选择它是商业区还是工业区。嗯?分成两个?在考虑若是所有的c数组不论该点选怎么都能产生贡献,我们最后减去最小的多算的贡献就好了。

    注意这所谓最小的贡献必须建立在每一块区域都被明确的选择了类型上

    于是乎,很容易就可以想到求最小的贡献就是直接最小割了

    那么如何建图?

    (相同的有额外收益) 则源点向所有点连商业区的收益,所有点向汇点连工业区的收益,相邻的点连双向边额外的收益 

    答案就是总收益减去最小割

    T1就是这样

    #include<bits/stdc++.h>
    using namespace std;
    
    const int inf=1e9+7;
    const int maxn=100+15;
    int n,m,tot=-1,s,t;
    int head[maxn*maxn],c[maxn][maxn],chead[maxn*maxn],vis[maxn*maxn];
    int l[4]={1,0},r[4]={0,1};
    struct EDGE
    {
        int to,next,cap;
    }edge[maxn<<15];
    inline int read()
    {
        char ch=getchar();
        int s=0,f=1;
        while (!(ch>='0'&&ch<='9')) {if (ch=='-') f=-1;ch=getchar();}
        while (ch>='0'&&ch<='9') {s=(s<<3)+(s<<1)+ch-'0';ch=getchar();}
        return s*f;
    }
    int get(int x,int y)
    {
        return (x-1)*m+y;
    }
    void add(int x,int y,int z1,int z2)
    {
        edge[++tot]=(EDGE){y,head[x],z1};
        head[x]=tot;
        edge[++tot]=(EDGE){x,head[y],z2};
        head[y]=tot;
    }
    bool bfs()
    {
        memset(vis,0,sizeof(vis));
        queue <int> q;
        vis[s]=1;
        q.push(s);
        while (!q.empty())
        {
            int k=q.front();q.pop();
            for (int i=head[k];i!=-1;i=edge[i].next)
            {
                int y=edge[i].to;
                if (!vis[y]&&edge[i].cap)
                {
                    vis[y]=vis[k]+1;
                    q.push(y);
                }
            }
        }
        return vis[t]!=0;
    }
    int dfs(int x,int flow)
    {
        if (x==t||!flow) return flow;
        int f,a=0;
        for (int &i=chead[x];i!=-1;i=edge[i].next)
        {
            int y=edge[i].to;
            if (vis[y]==vis[x]+1&&(f=dfs(y,min(edge[i].cap,flow)))>0)
            {
                edge[i].cap-=f;
                edge[i^1].cap+=f;
                a+=f;
                flow-=f;
                if (flow==0) break;
            }
        }
        if (a==0) vis[x]=-1;
        return a;
    }
    int dinic()
    {
        int ans=0;
        while (bfs())
        {
            for (int i=0;i<=n*m+1;i++) chead[i]=head[i];
            ans+=dfs(s,inf);
        }
        return ans;
    }
    int main()
    {
        int ans=0;
        n=read();m=read();
        s=0;t=n*m+1;
        memset(head,-1,sizeof(head));
        for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        {
        int x=read();
        add(s,get(i,j),x,0);
        ans+=x;
    }
        for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        {
        int x=read();
        add(get(i,j),t,x,0);
        ans+=x;
    }
        for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        c[i][j]=read();
        for (int i=1;i<=n;i++)
        for (int j=1;j<=m;j++)
        for (int k=0;k<=1;k++)
        {
            int x1=i+l[k],y1=j+r[k];
            if (x1<=0||x1>n||y1<=0||y1>m) continue;
            add(get(i,j),get(x1,y1),c[i][j]+c[x1][y1],c[i][j]+c[x1][y1]);
            ans+=(c[i][j]+c[x1][y1]);
    }
        printf("%d",ans-dinic());
        return 0;
    }
  • 相关阅读:
    matlab中关于使用length导致的不稳定状况。
    matlab 批量读入文件夹中的指定文件类型 (目录级数不限)
    matlab中的图像裁剪,图像抽取,反转,镜像。
    反锐化掩模 unsharp masking【转载】
    matlab 将图像切分为N*N像素的小块
    Python2.7.3 Tkinter Entry(文本框) 说明
    基于JQuery的列表拖动排序
    MAC如何删除开机自启动程序
    MAC配置SVN服务器
    关于MAC清倒废纸篓,项目正在使用
  • 原文地址:https://www.cnblogs.com/xxzh/p/9276270.html
Copyright © 2011-2022 走看看