hdu3046 Pleasant sheep and big big wolf--Dinic算法 & 最小割

原题链接: http://acm.hdu.edu.cn/showproblem.php?pid=3046


题意:

n*m的矩阵中,把狼和羊放进格子中,一个格子一个动物,要求建围栏把狼困住,不能吃掉羊。建图即可,这也是难点,设置一个超级源点和超级汇点,源点指向所有狼,所有羊指向汇点,然后求最小切割就行了,当然了两个点的边权值都要设为无穷大,这样求解最小割就没问题了。


#define _CRT_SECURE_NO_DEPRECATE 

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>

using namespace std;

struct Node
{
	int v;
	int w;
	int next;
}node[40000 * 4 + 100];

int n, m;
int cas = 1;
int head[40010];
int d[40010 * 4];
int q[40010];
int h, r;
int num;
int s, t;

void add(int u, int v, int w)
{
	node[num].v = v;
	node[num].w = w;
	node[num].next = head[u];
	head[u] = num++;

	node[num].v = u;
	node[num].w = 0;
	node[num].next = head[v];
	head[v] = num++;
}

bool bfs()
{
	memset(d, 0, sizeof(d));
	d[s] = 1;
	h = 0;
	r = 1;
	q[1] = s;
	while (h < r)
	{
		int u = q[++h];
		for (int i = head[u]; i != -1; i = node[i].next)
		{
			int v = node[i].v;
			if (d[v] == 0 && node[i].w>0)
			{
				d[v] = d[u] + 1;
				q[++r] = v;
				
			}
		}
	}
	if (d[t])
		return 1;
	return 0;
}

int dfs(int u, int flow)
{
	int a = 0;
	int ans = 0;
	if (u == t)
		return flow;

	for (int i = head[u]; i != -1; i = node[i].next)
	{
		int v = node[i].v;
		if (node[i].w > 0 && d[v] == d[u] + 1 && (a = dfs(v, min(flow, node[i].w))))
		{
			node[i].w -= a;
			node[i ^ 1].w += a;
			ans += a;
			if (ans == flow)//u节点下的路线找到的值等于u节点前最小权值,u节点以后的路线就不用找了
				return flow;
		}
	}
	if (ans == 0)//如果找不到,该路线就不用找了,直接赋值0,断开该路
		d[u] = 0;
	return ans;
}

int dinic()
{
	int sum = 0;
	int temp = 0;
	while (bfs())
		sum += dfs(s, INT_MAX);
	
	return sum;
}

int main()
{
	int x;
	while (~scanf("%d%d", &n, &m))
	{
		memset(head, -1, sizeof(head));
		num = 0;
		s = 0;
		t = n*m + 1;

		for (int i = 1; i <= n; i++)
		{
			for (int j = 1; j <= m; j++)
			{
				scanf("%d", &x);
				if (x == 1)
					add(s, (i - 1)*m + j, INT_MAX);
				else if (x == 2)
					add((i - 1)*m + j, t, INT_MAX);

				if (i - 1 >= 1)
					add((i - 1)*m + j, (i - 2)*m + j, 1);
				if (i + 1 <= n)
					add((i - 1)*m + j, i*m + j, 1);
				if (j - 1 >= 1)
					add((i - 1)*m + j, (i - 1)*m + j - 1, 1);
				if (j + 1 <= m)
					add((i - 1)*m + j, (i - 1)*m + j + 1, 1);
			}
		}

		printf("Case %d:\n%d\n", cas++, dinic());
	}
	return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值