• 并不对劲的方格取数问题


    题目描述

    在一个有 m*n 个方格的棋盘中,每个方格中有一个正整数。现要从方格中取数,使任意 2 个数所在方格没有公共边,且取出的数的总和最大。试设计一个满足要求的取数算法。对于给定的方格棋盘,按照取数要求编程找出总和最大的数。

    输入输出格式

    输入格式:

    第 1 行有 2 个正整数 m 和 n,分别表示棋盘的行数和列数。接下来的 m 行,每行有 n 个正整数,表示棋盘方格中的数。

    输出格式:

    程序运行结束时,将取数的最大总和输出

    输入输出样例

    输入样例
    3 3
    1 2 3
    3 2 3
    2 3 1 
    输出样例
    11

    说明

    m,n<=100

    ***********************怕不是要dp********************

    这道题如果不是在网络流24题中,我可能真把它当dp了。

    用最大流最小割定理求出至少需要不取多少数才能把剩下的数分开。

    #include<iostream>
    #include<iomanip>
    #include<cstring>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #define ll long long
    #define maxk 110
    #define maxm 200010
    #define maxn 20010
    using namespace std;
    ll n,m,a[maxk][maxk],sum;
    ll v[maxm],fir[maxn],fl[maxm],nxt[maxm],cnt;
    ll ss,tt,dis[maxn],vis[maxn],maxflow,inf[5];
    ll read()
    {
        ll x=0,f=1;
        char ch=getchar();
        while(isdigit(ch)==0&&ch!='-')ch=getchar();
        if(ch=='-')ch=getchar(),f=-1;
        while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    void addedge(ll u1,ll v1,ll fl1)
    {
        v[cnt]=v1,fl[cnt]=fl1,nxt[cnt]=fir[u1],fir[u1]=cnt++;
        v[cnt]=u1,fl[cnt]=0,nxt[cnt]=fir[v1],fir[v1]=cnt++;
    }
    ll bfs()
    {
        memset(dis,-1,sizeof(dis));
        memset(vis,0,sizeof(vis));
        queue<ll>q;
        vis[ss]=1;
        dis[ss]=0;
        q.push(ss);
        while(!q.empty())
        {
            ll u=q.front();q.pop();
            for(ll k=fir[u];k!=-1;k=nxt[k])
            {
                ll vv=v[k];
                if(fl[k]>0)
                {
                    if(dis[vv]>dis[u]+1 || dis[vv]==-1)
                    {
                        dis[vv]=dis[u]+1;
                        if(!vis[vv])q.push(vv);
                        vis[vv]=1;
                    }
                }
            }
            vis[u]=0;
        }
        return dis[tt]==-1?0:1;
    }
    ll dfs(ll u,ll nowflow)
    {
        ll tmp,sum=0;
        if(u==tt || nowflow==0)return nowflow;
        for(ll k=fir[u];k!=-1;k=nxt[k])
        {
            if(nowflow<=0)break;
            ll vv=v[k];
            if(fl[k]>0 && dis[u]+1==dis[vv] 
            && (tmp=dfs(vv,min(nowflow,fl[k])))>0)
            {
                nowflow-=tmp;
                sum+=tmp;
                fl[k]-=tmp;
                fl[k^1]+=tmp;
            }
        }
        return sum;
    }
    void add(ll x,ll y)
    {
        ll z=x*m+y;
        if((x+y)&1)
        {
            addedge(ss,z,inf[0]);
            addedge(z,z+n*m,a[x][y]);
            if(x>0)addedge(z+n*m,(x-1)*m+y,inf[0]);
            if(x<n-1)addedge(z+n*m,(x+1)*m+y,inf[0]);
            if(y>1)addedge(z+n*m,x*m+y-1,inf[0]);
            if(y<m)addedge(z+n*m,x*m+y+1,inf[0]);
        }
        else
        {
            addedge(z,z+n*m,a[x][y]);
            addedge(z+n*m,tt,inf[0]);
        }
    }
    int main() 
    {
        memset(inf,0x7f,sizeof(inf));
        memset(fir,-1,sizeof(fir));
        n=read(),m=read();ss=0,tt=n*m+n*m+1;
        for(ll i=0;i<n;i++)
        {
            for(ll j=1;j<=m;j++)
            {
                a[i][j]=read();
                sum+=a[i][j];
                add(i,j);
            }
        }
        /*for(ll i=0;i<=tt;i++)
        {
            cout<<i<<":";
            for(ll k=fir[i];k!=-1;k=nxt[k])
            {
                cout<<v[k]<<" "<<fl[k]<<endl;
            }
        }*/
        while(bfs())
        {
            maxflow+=dfs(ss,inf[0]);
        }
        cout<<sum-maxflow;
        return 0;
    }
    View Code

    听说网络流可以解决绝大部分问题(就是时间复杂度……),你信吗?

  • 相关阅读:
    AtCoder Grand Contest 015 题解
    AtCoder Grand Contest 014 题解
    AtCoder Grand Contest 013 题解
    AtCoder Grand Contest 012 题解
    AtCoder Grand Contest 011 题解
    AtCoder Grand Contest 010 题解
    AtCoder Grand Contest 009 题解
    NOIP2017 Day2 题解
    博客园主题备份
    多项式全家桶
  • 原文地址:https://www.cnblogs.com/xzyf/p/8317523.html
Copyright © 2020-2023  润新知