P2598 [ZJOI2009]狼和羊的故事(网络流)

在这里插入图片描述
我个人的理解:
可以先对原图进行建模为下图
在这里插入图片描述
其左端是狼,右端为羊,中间是连接狼和羊的路
现在为了让狼吃不到样,就要隔断狼和羊之间的连接
也就是
在这里插入图片描述
在这里,我们需要隔断狼和羊之间的连接,也就是转化成最小割问题
很明显,这里的路权均为1
然后分别建立源点和汇点,分别连接狼与羊,边权为inf,进行求解最小割即可

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 2e5+7; 
int dir[4][4] = {{1,0},{0,1},{-1,0},{0,-1}};
struct node{
	int to,from;
	ll w;
}edge[MAXN];
class Dinic:node{
	public:
		const int inf =0x3f3f3f3f;  
		int head[MAXN],now[MAXN],cnt=1,n,s,t;//点数,源点,汇点
		int dep[MAXN],ans;
		void Add(int u,int v,ll w)
		{
			cnt++;
			edge[cnt].to = v;
			edge[cnt].w = w;
			edge[cnt].from = head[u];
			head[u] = cnt;
		}
		void add(int u,int v,int w){
			Add(u,v,w);
			Add(v,u,0);
		}
		int bfs()
		{
			for(int i=1;i<=n;i++)
				dep[i] = inf;
			queue<int>q;
			q.push(s);
			dep[s] = 0;
			now[s] = head[s];
			while(!q.empty())
			{
				int so = q.front();
				q.pop();
				for(int i=head[so];i;i=edge[i].from)
				{
					int to = edge[i].to;
					if(edge[i].w&&dep[to] == inf)
					{
						q.push(to);
						now[to] = head[to];
						dep[to] = dep[so]+1;
						if(to==t) return 1;
					}
				}
			}
			return 0;
		}
		int dfs(int x,ll sum)
		{
			if(x==t)return sum;
			ll k,res=0;
			for(int i=now[x];i&&sum;i = edge[i].from)
			{
				now[x] = i;//当前弧优化
				int to = edge[i].to;
				if(edge[i].w&&dep[to]==dep[x]+1)
				{
					k = dfs(to,min(sum,edge[i].w));
					if(k==0) dep[to] = inf;
					edge[i].w-=k;
					edge[i^1].w+=k;
					res+=k;//流量和 
					sum-=k;//剩余流量 
				} 
			}
			return res;
		}
		int dini(){
			while(bfs())ans+=dfs(s,inf);
			return ans;
		}
};
Dinic d;
int n,m;
int cal(int x,int y)
{
	return (x-1)*m+y;
}
int a[105][105];
int main()
{
	cin>>n>>m;
	d.n = n*m+2;
	d.s = n*m+1;d.t = n*m+2;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&a[i][j]);
			if(a[i][j]==1)d.add(d.s,cal(i,j),d.inf);
			if(a[i][j]==2)d.add(cal(i,j),d.t,d.inf);
		}
	}
	for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            for(int k=0;k<4;k++)	
            {
                int tx=i+dir[k][0];
                int ty=j+dir[k][1];
                if(tx<=n and ty<=m and tx>=1 and ty>=1)
                    d.add(cal(i,j),cal(tx,ty),1);
            }
    cout<<d.dini()<<endl;        
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值