hdu 3046 Pleasant sheep and big big wolf(sap最大流)

开始在hrbust上做的,数据改为20,用矩阵和普通的最大流算法均可以过!后来查的时候看到了hdu上的,数据比那个大很多,点数最多可达40000,第一次MLE,换成邻接表,第二次TLE,果断换算法,sap轻松秒过!

建图的方法就是远点连2, 终点连1,容量inf, 把每个挨着的格子连起来,容量1,求最小割! 这里求最小割很好理解,就像从一个2开始走,向1走,然后每次走都会经过一个格子的边界,不管有多少只wolf经过这个边界,只需要一个栅栏即可,也就是每个边界只有一个位置放栅栏,一般有三个或4个边界,这样,就能够建成一个从所有的2开始走向1的图,只要删除最小割上的点,就能阻止从1s和2s的连通!

下面是代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;


const int MAXN=40010;
const int MAXM=2000020;
const int INF = 0x3fffffff;
struct Node
{
	int to,next,cap;
}edge[MAXM];//注意是MAXM
int tol, n, m;
int head[MAXN];
int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN];

void addedge(int u,int v,int w,int rw=0)
{
	edge[tol].to=v;edge[tol].cap=w;edge[tol].next=head[u];head[u]=tol++;
	edge[tol].to=u;edge[tol].cap=rw;edge[tol].next=head[v];head[v]=tol++;
}
int sap(int start,int end,int nodenum)
{
	memset(dis,0,sizeof(dis));
	memset(gap,0,sizeof(gap));
	memcpy(cur,head,sizeof(head));
	int u=pre[start]=start,maxflow=0,aug=-1;
	gap[0]=nodenum;
	while(dis[start]<nodenum)
	{
		loop:
		for(int &i=cur[u];i!=-1;i=edge[i].next)
		{
			int v=edge[i].to;
			if(edge[i].cap&&dis[u]==dis[v]+1)
			{
				if(aug==-1||aug>edge[i].cap)
					aug=edge[i].cap;
				pre[v]=u;
				u=v;
				if(v==end)
				{
					maxflow+=aug;
					for(u=pre[u];v!=start;v=u,u=pre[u])
					{
						edge[cur[u]].cap-=aug;
						edge[cur[u]^1].cap+=aug;
					}
					aug=-1;
				}
				goto loop;
			}
		}
		int mindis=nodenum;
		for(int i=head[u];i!=-1;i=edge[i].next)
		{
			int v=edge[i].to;
			if(edge[i].cap&&mindis>dis[v])
			{
				cur[u]=i;
				mindis=dis[v];
			}
		}
		if((--gap[dis[u]])==0)break;
		gap[dis[u]=mindis+1]++;
		u=pre[u];
	}
	return maxflow;
}

int o[205][205];
int main()
{
    int icase = 1;
    while ( scanf("%d%d", &n, &m) != EOF ) {
        int S = 0, T = n*m+1; tol = 0;
        memset( head, -1, sizeof(head));
        for ( int i = 1; i <= n; ++i ) for ( int j = 1; j <= m; ++j ) {
                scanf("%d", &o[i][j]);
                int u = (i-1)*m+j;
                if ( o[i][j] == 1 ) addedge( u, T, INF, 0 );
                else if ( o[i][j] == 2 ) addedge( S, u, INF, 0 );
                if ( i > 1 ) addedge( u, u-m, 1, 0 );
                if ( i < n ) addedge( u, u+m, 1, 0 );
                if ( j > 1 ) addedge( u, u-1, 1, 0 );
                if ( j < m ) addedge( u, u+1, 1, 0 );
        }
        printf("Case %d:\n%d\n", icase++, sap( S, T, T+1));
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值