方格取数(1)

http://acm.hdu.edu.cn/showproblem.php?pid=1565

算法:

最大点权独立集 = 总点数 - 最小点权覆盖集

最小点权覆盖集 = 最小割 = 最大流


点独立集:点独立集是无向图G的子集,该子集的导出子图不含边,即任两个在该集合中的点在原图中都不相邻。

最大点权独立集:在带权无向图G中,点权之和最大的独立集。


点覆盖集:点覆盖集是无向图G的子集,使得原图内所有边都至少有一个端点在该集合内。

最小点权覆盖集:在带权无向图G中,点权之和最小的覆盖集。


思路:

要求最大点权独立集,根据算法只需求最小点权覆盖集,也就是求最大流问题。

先染色,纵横坐标之和满足 (i+j)%2 == 0 的点染白色,与它相邻的点染黑色;

源点s与每个白点相连,容量为该点的数字;

每个白点与它相邻的黑点相连,容量为无穷大;

每个黑点与汇点相连,容量为该点上的数字;

对这个图求最大流maxflow,用所有数字和减maxflow就是答案。



#include<stdio.h>
#include<string.h>
#include<queue>
#include<algorithm>
using namespace std;

const int INF = 0x3f3f3f3f;
int n,sum,s,t;
int map[30][30];
int cap[500][500];//容量
int flow[500][500];//流量
int p[500];//记录前驱
int a[500];//记录该路径上的最小增量
int maxflow;
queue<int> que;
void E_K()//bfs找增光路
{
	while(!que.empty())
		que.pop();
	memset(flow,0,sizeof(flow));

	while(1)
	{
		for(int i = 0; i <= t; i++)
			p[i] = i;
		memset(a,0,sizeof(a));
		a[s] = INF;
		que.push(s);
		while(!que.empty())
		{
			int u = que.front();
			que.pop();

			for(int v = 0; v <= t; v++)
			{
				if(!a[v] && flow[u][v] < cap[u][v])
				{
					p[v] = u;
					que.push(v);
					a[v] = min(a[u],cap[u][v]-flow[u][v]);
				}
			}
		}
		if(a[t] == 0) break;
		for(int u = t; u != s; u = p[u])
		{
			flow[p[u]][u] += a[t];
			flow[u][p[u]] -= a[t];
		}
		maxflow += a[t];
	}
}

int main()
{
	while(~scanf("%d",&n))
	{
		sum = 0;
		for(int i = 1; i <= n; i++)
		{
			for(int j = 1; j <= n; j++)
			{
				scanf("%d",&map[i][j]);
				sum += map[i][j];
			}
		}

		memset(cap,0,sizeof(cap));
		s = 0;
		t = n*n+1;

		for(int i = 1; i <= n; i++)
		{
			for(int j = 1; j <= n; j++)
			{
				int it = (i-1)*n+j;
				if((i+j)%2 == 0)
					cap[s][it] = map[i][j];

				else
					cap[it][t] = map[i][j];
			}
		}

		for(int i = 1; i <= n; i++)
		{
			for(int j = 1; j <= n; j++)
			{
				if((i+j)%2 == 0)
				{
					if(j < n)
						cap[(i-1)*n+j][(i-1)*n+j+1] = INF;
					if(j > 1)
						cap[(i-1)*n+j][(i-1)*n+j-1] = INF;
					if(i > 1)
						cap[(i-1)*n+j][(i-1)*n+j-n] = INF;
					if(i < n)
						cap[(i-1)*n+j][(i-1)*n+j+n] = INF;
				}
			}
		}
		maxflow = 0;
		E_K();
		printf("%d\n",sum-maxflow);
	}
	return 0;
}



你可能感兴趣的:(Algorithm,图论,流量)