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


    题目描述

    在一个有 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

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

  • 相关阅读:
    spring的好处
    2.3 java中类路径
    java的编译器为什么会自动编译java文件
    oracle添加字段或者删除字段-转载
    sql 取新的列名含义
    window.onload =writeMessage(); 与window.onload =writeMessage;的区别
    HTML DOM 之<textare>标签
    最新学习网址大全
    C#读写txt文件的两种方法介绍
    固定分隔符字符串与数组互转及ArrayList与数组(Array)互转
  • 原文地址:https://www.cnblogs.com/xzyf/p/8317523.html
Copyright © 2020-2023  润新知