bzoj1475 求解最大独立集

上一篇文章我写了有关二分图的相关定理和公

式:http://blog.csdn.net/qq_34564984/article/details/52778763


而这道题,很显然,行+列为奇数和偶数的点是不会有边相连的,因此,可以将相邻

点建边,则此题为裸的求最大独立点权集的题


最大独立集+最小点权覆盖=总权值


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


跑一遍最大流即可


附代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<climits>
#include<queue>
#define N 100001
#define M 400001
#define inf INT_MAX
using namespace std;
int n,S,T,all;
int map[50][50],m[50][50];
int id;
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
int head[N],pos,cur[N];
struct edge{int to,next,c;}e[M];
void add(int a,int b,int c)
{
	e[pos].to=b,e[pos].next=head[a],e[pos].c=c,head[a]=pos;pos++;
	e[pos].to=a,e[pos].next=head[b],e[pos].c=0,head[b]=pos;pos++;
}
void init()
{pos=0;memset(head,-1,sizeof(head));}
queue<int>Q;bool vis[N];int d[N];
bool bfs()
{
	memset(vis,0,sizeof(vis));
	vis[S]=1,d[S]=0;Q.push(S);
	while(!Q.empty())
		{
			int u=Q.front();Q.pop();
			for(int i=head[u];i!=-1;i=e[i].next)
				{
					int v=e[i].to;
					if(!vis[v]&&e[i].c>0)
						{
							vis[v]=1;
							d[v]=d[u]+1;
							Q.push(v);
						}
				}
		}
	return vis[T];
}
int dfs(int u,int a)
{
	if(u==T||a==0)return a;
	int f,flow=0;
	for(int &i=cur[u];i!=-1;i=e[i].next)
		{
			int v=e[i].to;
			if(d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].c)))>0)
				{
					a-=f;
					e[i].c-=f;
					e[i^1].c+=f;
					flow+=f;
					if(a==0)break;
				}
		}
	return flow;
}
int dinic()
{
	int ans=0;
	while(bfs())
		{
			for(int i=S;i<=T;i++)cur[i]=head[i];
			ans+=dfs(S,inf);
		}
	return ans;
}
int main()
{
	scanf("%d",&n);
	S=0,T=n*n+1;
	init();
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			{
				scanf("%d",&map[i][j]);
				id++;m[i][j]=id;all+=map[i][j];
			}
	for(int u=1;u<=n;u++)
		for(int v=1;v<=n;v++)
			{
				if((u+v)%2)
					{
						add(S,m[u][v],map[u][v]);
						if(u>=2)add(m[u][v],m[u-1][v],inf);
						if(v>=2)add(m[u][v],m[u][v-1],inf);
					}
				else
					{
						add(m[u][v],T,map[u][v]);
						if(u>=2)add(m[u-1][v],m[u][v],inf);
						if(v>=2)add(m[u][v-1],m[u][v],inf);
					}
			}
	printf("%d\n",all-dinic());
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值