• hdu 1569 方格取数(2) 最大点权独立集


    方格取数(2)

    Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
    Total Submission(s): 5425    Accepted Submission(s): 1695


    Problem Description
    给你一个m*n的格子的棋盘,每个格子里面有一个非负数。
    从中取出若干个数,使得任意的两个数所在的格子没有公共边,就是说所取数所在的2个格子不能相邻,并且取出的数的和最大。
     
    Input
    包括多个测试实例,每个测试实例包括2整数m,n和m*n个非负数(m<=50,n<=50)
     
    Output
    对于每个测试实例,输出可能取得的最大的和
     
    Sample Input
    3 3 75 15 21 75 15 28 34 70 5
     
    Sample Output
    188
     
     
    题意就是求最大点权独立集。
     
    点覆盖集:是无向图G点一个点集,使得该图中所有边都至少有一个端点在该集合内。
    点独立集:是无向图的一个点集,使得任两个在该集合中的点在原图中都不相邻。
    最小点覆盖集(minimum vertex covering set,MinVCS)是在无向图中,点数最少的点覆盖集。
    最大点独立集(maximum vertex independent set,MaxVIS)是在无向图中,点数最多的点独立集。
    以上两个问题在二分图中都可以用最大匹配模型来快速解决。
     
    更为一般的问题:
    最小点权覆盖集(minimum weight vertex covering set,MinWVCS)是在带点权无向图G中,点权之和最小的点覆盖集。
    最大点权独立集(maximum weight vertex independent set,MaxWVIS)是在带点权无向图中,点权之和最大的点独立集。
     
    最小点权覆盖问题建图方法:
    在原图点基础上增加源点s和汇点t。讲二分图中每条边替换为容量为正无穷点有向边。
    添加s到X集合中点的有向边,容量为该点的权值。添加集合Y中的点到t的有向边,容量为该点的权值。然后求最小割。
     
    最大点独立集 = 全集 - 最小点覆盖集
    最大点权独立集 = 全集 - 最小点权覆盖集
    最大点权独立集点权之和 = 所有点权之和 - 最小点权覆盖集点权之和
     
    所以此题求最大点权独立集 就是全集 - 最小点权覆盖集。
    那么把方格中的点分为两个部分X和Y。
    增加源点s和汇点t。X和Y点边即X中的点与其相邻点Y中的点连接一条有向边。
    s到X点边为每个点的权值。Y到t点边为每个点的权值。X到Y的边容量为正无穷。
    可以这样考虑,因为X中的点连到和它相邻的Y中的点的边都是题目中不允许点。
    所以相当于选出这样的非法边,然后去掉最小点。那么剩下来就是最大点。
     
    bzoj1324 Exca王者之剑和这题类似
    #include <bits/stdc++.h>
    using namespace std;
    #define maxn 55
    const int inf = 0x3f3f3f3f;
    int M, N;
    int mp[maxn][maxn];
    int mark[maxn][maxn];
    int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    struct Edge
    {
        int from, to, cap, flow;
        Edge(int f, int t, int c, int fl)
        {
            from = f; to = t; cap = c; flow = fl;
        }
    };
    vector <Edge> edges;
    vector <int> G[maxn*maxn];
    int s, t, n, m;
    int cur[maxn*maxn], vis[maxn*maxn], d[maxn*maxn];
    void AddEdge(int from, int to, int cap)
    {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }
    bool bfs()
    {
        memset(vis, 0, sizeof(vis));
        d[s] = 0; vis[s] = 1;
        queue <int> q;
        q.push(s);
        while(!q.empty())
        {
            int u = q.front(); q.pop();
            for(int i = 0; i < G[u].size(); i++)
            {
                Edge &e = edges[G[u][i]];
                if(!vis[e.to] && e.cap > e.flow)
                {
                    vis[e.to] = 1;
                    d[e.to] = d[u]+1;
                    q.push(e.to);
                }
            }
        }
        return vis[t];
    }
    int dfs(int x, int a)
    {
        if(x == t || a == 0) return a;
        int flow = 0, f;
        for(int &i = cur[x]; i < G[x].size(); i++)
        {
            Edge &e = edges[G[x][i]];
            if(d[x]+1 == d[e.to] && (f = dfs(e.to, min(a, e.cap-e.flow))) > 0)
            {
                e.flow += f;
                edges[G[x][i]^1].flow -= f;
                flow += f;
                a -= f;
                if(a == 0) break;
            }
        }
        return flow;
    }
    int Maxflow()
    {
        int flow = 0;
        while(bfs())
        {
            memset(cur, 0, sizeof(cur));
            flow += dfs(s, inf);
        }
        return flow;
    }
    bool judge(int x, int y)
    {
        if(x >= 1 && x <= N && y >= 1 && y <= M) return true;
        return false;
    }
    int main()
    {    
        while(~scanf("%d%d", &N, &M))
        {
            edges.clear();
            for(int i = 0; i < maxn*maxn; i++) G[i].clear();
            int sum = 0;
            for(int i = 1; i <= N; i++)
            {
                for(int j = 1; j <= M; j++)
                {
                    scanf("%d", &mp[i][j]);
                    sum += mp[i][j];
                }
            }
            s = 0; t = N*M+1;
            for(int i = 1; i <= N; i++)
            {
                for(int j = 1; j <= M; j++)
                {
                    if((i+j)%2 == 0) 
                    {
                        AddEdge(s, (i-1)*M+j, mp[i][j]);    
                        if(i > 1) AddEdge((i-1)*M+j, (i-2)*M+j, inf);
                        if(j > 1) AddEdge((i-1)*M+j, (i-1)*M+j-1, inf);
                        if(i < N) AddEdge((i-1)*M+j, i*M+j, inf);
                        if(j < M) AddEdge((i-1)*M+j, (i-1)*M+j+1, inf);
                    }
                    else AddEdge((i-1)*M+j, t, mp[i][j]);
                }
            }
            printf("%d
    ", sum - Maxflow());
        }
    
    }
    
     
  • 相关阅读:
    Linux进程间通信分类 以及 pipe的原理实现
    单链表的快速排序
    再谈二分查找
    数据库范式
    二分查找法浅析
    C# Observer设计模式
    C# 交错数组浅析
    C语言初学 数学中带根号的复杂计算问题
    C语言初学 计算三角形面积问题
    C语言初学 简单定义圆的面积计算问题
  • 原文地址:https://www.cnblogs.com/titicia/p/4695226.html
Copyright © 2020-2023  润新知