• P2774 方格取数问题


    题目背景

    none!

    题目描述

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

    输入输出格式

    输入格式:

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

    输出格式:

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

    输入输出样例

    输入样例#1: 复制
    3 3
    1 2 3
    3 2 3
    2 3 1 
    输出样例#1: 复制
    11

    说明

    m,n<=100

    //状压DP
    //。貌似状压不能过,因为n,m都是<=100的,
    //这样找出来就是100个二进制位,也就是2^100 
    //.但是不知道为啥他们都能AC
    //写写试试 
    
    //91分封顶。
    //数据还是太水。 
    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    
    const int N=1e2+5;
    const int M=1e5+5;
    
    inline int read()
    {
        char c=getchar();int num=0;
        for(;!isdigit(c);c=getchar());
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num;
    }
    
    int n,m;
    int map[N][N];
    int sum[N][M];
    int opt[N],cnt;
    int dp[N][M];
    
    void init(int line,int id)
    {
        for(int i=1;i<=m;++i)
            if(opt[id]>>(i-1)&1)
                sum[line][id]+=map[line][i];
    }
    
    int main()
    {
        n=read(),m=read();
        for(int i=0;i<(1<<m);++i)
        {
            if(!(i&(i<<1)||i&(i>>1)))    //找出不会有两个1相邻的状态 
                opt[++cnt]=i;
            if(i>2&&(i>>(i-1))&((i-1)>>(i-2)))
                i+=1<<i-2,--i;
        }
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
                map[i][j]=read();
        for(int i=1;i<=cnt;++i)
            init(1,i),dp[1][i]=sum[1][i];
        for(int i=2;i<=n;++i)
            for(int j=1;j<=cnt;++j)
                init(i,j);
        for(int i=2;i<=n;++i)    //枚举第几行 
        {
            for(int j=1;j<=cnt;++j)        //枚举第i行的状态 
            {
                for(int k=1;k<=cnt;++k)        //枚举第i-1行的状态 
                {
                    if(opt[j]&opt[k])
                        continue;
                    dp[i][j]=max(dp[i][j],dp[i-1][k]+sum[i][j]);
                }
            }
        }
        int ans=0;
        for(int i=1;i<=cnt;++i)
        {
    //        printf("%d %d
    ",i,dp[n][i]);
            ans=max(ans,dp[n][i]);
        }
        printf("%d",ans);
        return 0;
    }
    91分状压
    //网络流
    //方格取数
    
    //思考一下这个问题的性质
    //就是个棋盘的黑白染色问题 
    //假设(i+j)&1==1的格子是黑格
    //那么我们可以建一个二分图
    // 
    
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue> 
    using namespace std;
    
    const int N=1e5+5;
    const int INF=0x3f3f3f3f;
    
    inline int read()
    {
        char c=getchar();int num=0,f=1;
        for(;!isdigit(c);c=getchar())
            f=f=='-'?-1:f;
        for(;isdigit(c);c=getchar())
            num=num*10+c-'0';
        return num*f;
    }
    
    int n,m,S,T;
    int head[N],from[N],num_edge;
    struct Edge
    {
        int v,flow,nxt;
    }edge[N];
    
    void add_edge(int u,int v,int flow)
    {
        edge[++num_edge].v=v;
        edge[num_edge].flow=flow;
        edge[num_edge].nxt=head[u];
        head[u]=num_edge;
    }
    
    int dep[N];
    bool bfs()
    {
        queue<int> que;
        int now,v;
        for(int i=S;i<=T;++i)
            dep[i]=0,from[i]=head[i];
        dep[S]=1;
        que.push(S);
        while(!que.empty())
        {
            now=que.front(),que.pop();
            for(int i=head[now];i;i=edge[i].nxt)
            {
                v=edge[i].v;
                if(!dep[v]&&edge[i].flow)
                {
                    dep[v]=dep[now]+1;
                    if(v==T)
                        return 1;
                    que.push(v);
                }
            }
        }
        return 0;
    }
    
    int dfs(int now,int flow)
    {
        if(now==T||!flow)
            return flow;
        int outflow=0,tmp;
        for(int i=head[now],v;i;i=edge[i].nxt)
        {
            if(!edge[i].flow)
                continue;
            v=edge[i].v;
            if(dep[v]!=dep[now]+1)
                continue;
            tmp=dfs(v,min(flow,edge[i].flow));
            if(!tmp)
                continue;
            edge[i].flow-=tmp;
            edge[i^1].flow+=tmp;
            flow-=tmp;
            outflow+=tmp;
            if(!flow)
                break;
        }
        dep[now]=0;
        return outflow;
    }
    
    #define A m*(i-1)+j
    int ans;
    int main()
    {
        num_edge=1;
        n=read(),m=read();
        T=n*m+1;
        for(int i=1,a;i<=n;++i)
        {
            for(int j=1;j<=m;++j)
            {
                a=read();
                ans+=a;
                if((i+j)%2==0)
                {
                    add_edge(A,T,a);
                    add_edge(T,A,0);
                    continue;
                }
                add_edge(S,A,a);
                add_edge(A,S,0);
                if(i>1)
                {
                    add_edge(A,A-m,INF);
                    add_edge(A-m,A,0);
                }
                if(j>1)
                {
                    add_edge(A,A-1,INF);
                    add_edge(A-1,A,0);
                }
                if(i<n)
                {
                    add_edge(A,A+m,INF);
                    add_edge(A+m,A,0);
                }
                if(j<m)
                {
                    add_edge(A,A+1,INF);
                    add_edge(A+1,A,0);
                }
            }
        }
        while(bfs())
        {
            ans-=dfs(S,INF);
        }
        printf("%d",ans);
        return 0;
    }
  • 相关阅读:
    安装jdk
    chrome
    Jenkins启动
    Red Hat Linux分辨率调整
    Jemeter第一个实例
    grep与正则表达式
    使用ngx_lua构建高并发应用
    UML建模之时序图(Sequence Diagram)
    secureCRT mac 下破解
    跨域通信的解决方案JSONP
  • 原文地址:https://www.cnblogs.com/lovewhy/p/9097042.html
Copyright © 2020-2023  润新知