[网络流24题]方格取数 最大点权独立集

来源:互联网 发布:淘宝店铺最高等级 编辑:程序博客网 时间:2024/06/10 12:44

题目链接

大牛思路:

【问题分析】

二分图点权最大独立集,转化为最小割模型,从而用最大流解决。

【建模方法】

首先把棋盘黑白染色,使相邻格子颜色不同,所有黑色格子看做二分图X集合中顶点,白色格子看做Y集合顶点,建立附加源S汇T。

1、从S向X集合中每个顶点连接一条容量为格子中数值的有向边。
2、从Y集合中每个顶点向T连接一条容量为格子中数值的有向边。
3、相邻黑白格子Xi,Yj之间从Xi向Yj连接一条容量为无穷大的有向边。

求出网络最大流,要求的结果就是所有格子中数值之和减去最大流量。

【建模分析】

这是一个二分图最大点权独立集问题,就是找出图中一些点,使得这些点之间没有边相连,这些点的权值之和最大。独立集与覆盖集是互补的,求最大点权独立集可以转化为求最小点权覆盖集(最小点权支配集)。最小点权覆盖集问题可以转化为最小割问题解决。结论:最大点权独立集 = 所有点权 - 最小点权覆盖集 = 所有点权 - 最小割集 = 所有点权 - 网络最大流。

对于一个网络,除去冗余点(不存在一条ST路径经过的点),每个顶点都在一个从S到T的路径上。割的性质就是不存在从S到T的路径,简单割可以认为割边关联的非ST节点为割点,而在二分图网络流模型中每个点必关联到一个割点(否则一定还有增广路,当前割不成立),所以一个割集对应了一个覆盖集(支配集)。最小点权覆盖集就是最小简单割,求最小简单割的建模方法就是把XY集合之间的变容量设为无穷大,此时的最小割就是最小简单割了。

有关二分图最大点权独立集问题,更多讨论见《最小割模型在信息学竞赛中的应用》作者胡伯涛。

#include<bits/stdc++.h>#define MAXN 1010#define MAXM 10000100#define INF 0x3f3f3f3fusing namespace std;typedef long long ll;const int maxn = 100005;int mm[1005][1005];int n,m;int dir[4][2] =  { {1,0},{-1,0},{0,1},{0,-1} };int col[1005][1005];struct Edge{    int from, to, cap, flow, next;};Edge edge[MAXM];int head[MAXN], cur[MAXN], edgenum;int dist[MAXN];bool vis[MAXN];int N, M,ss,tt;void init(){    edgenum = 0;    memset(head, -1, sizeof(head));}void addEdge(int u, int v, int w){    Edge E1 = {u, v, w, 0, head[u]};    edge[edgenum] = E1;    head[u] = edgenum++;    Edge E2 = {v, u, 0, 0, head[v]};    edge[edgenum] = E2;    head[v] = edgenum++;}bool BFS(int s, int t){    queue<int> Q;    memset(dist, -1, sizeof(dist));    memset(vis, false, sizeof(vis));    dist[s] = 0;    vis[s] = true;    Q.push(s);    while(!Q.empty())    {        int u = Q.front();        Q.pop();        for(int i = head[u]; i != -1; i = edge[i].next)        {            Edge E = edge[i];            if(!vis[E.to] && E.cap > E.flow)            {                dist[E.to] = dist[u] + 1;                if(E.to == t) return true;                vis[E.to] = true;                Q.push(E.to);            }        }    }    return false;}int DFS(int x, int a, int t){    if(x == t || a == 0) return a;    int flow = 0, f;    for(int &i = cur[x]; i != -1; i = edge[i].next)    {        Edge &E = edge[i];        if(dist[E.to] == dist[x] + 1 && (f = DFS(E.to, min(a, E.cap - E.flow), t)) > 0)        {            edge[i].flow += f;            edge[i^1].flow -= f;            flow += f;            a -= f;            if(a == 0) break;        }    }    return flow;}int Maxflow(int s, int t){    int flow = 0;    while(BFS(s, t))    {        memcpy(cur, head, sizeof(head));        flow += DFS(s, INF, t);    }    return flow;}void dfs(int x,int y,int cl){    col[x][y]=cl;    for(int i=0;i<4;i++)    {        int xx = x+dir[i][0];        int yy = y+dir[i][1];        if(xx<1 || xx>n||yy<1||yy>m||col[xx][yy]) continue;        if(cl==1)            dfs(xx,yy,2);        else            dfs(xx,yy,1);    }}int getnum(int x,int y){    return (x-1)*m+y;}int main(){//    freopen("data.txt","r",stdin);//    ios_base::sync_with_stdio(false);//    int T;//    scanf("%d",&T);    while(scanf("%d%d",&n,&m)==2)    {        int ans  = 0;        memset(col,0,sizeof(col));        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                scanf("%d",&mm[i][j]);                ans+=mm[i][j];            }        }        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                if(!col[i][j])                {                    dfs(i,j,1);                }            }        }//        for(int i=1;i<=n;i++)//        {//            for(int j=1;j<=m;j++)//            {//                cout << col[i][j]<<" ";//            }//            cout <<endl;//        }        init();        ss = 0;        tt = n*m+1;        for(int i=1;i<=n;i++)        {            for(int j=1;j<=m;j++)            {                if(col[i][j]==1)                {                    addEdge(ss,getnum(i,j),mm[i][j]);                    for(int d=0;d<4;d++)                    {                        int xx = i+dir[d][0];                        int yy = j+dir[d][1];                        if(xx<1 || xx>n || yy<1 || yy>m ||col[xx][yy]==1) continue;                        addEdge(getnum(i,j),getnum(xx,yy),INF);                    }                }                else                {                    addEdge(getnum(i,j),tt,mm[i][j]);                }            }        }        printf("%d\n",ans-Maxflow(ss,tt));    }    return 0;}
阅读全文
0 0