今日打卡:洛谷:P1263 [CEOI2002] Royal guards

家人们!今天又——————————来打卡啦!来看看今天的幸运签吧!

这次的运势还正常点,只是,我不玩我的世界啊!

好了!话不多说,上代码!

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <iostream> 
#include <queue>
#define MAXM 100100
#define MAXN 202
#define MAXN2 202*202
using namespace std;

const int INF=2147483647;

int wall[MAXN][MAXN][2]; //记录空格对应的横墙和竖墙 
int castle[MAXN][MAXN]; //城堡地形图 
int n,m,s,t; //n:x方向长度  m:y方向长度 这里注意,和题目给的是反过来的  s和t为超源超汇 
int maxflow=0;
int idbegin;  //从这个编号开始的边全部是连接竖墙和横墙的边 

struct EDGE
{
	int from,to,weight,next;
}edge[MAXM<<1]; //链式前向星存图 

int head[MAXN2<<1];
int deep[MAXN2<<1];
int cnt=0;

inline void add(int x,int y,int w)
{
	edge[cnt].from=x;
	edge[cnt].to=y;
	edge[cnt].weight=w;
	edge[cnt].next=head[x];
	head[x]=cnt++;
}

inline int convert(int x,int y)  //把二维的坐标映射到一维 
{
	return (x-1)*200+y;
}

void input()
{
	for (int i=0;i<=MAXN2<<1;i++)
		head[i]=-1;
	s=0;
	t=80001;
	cin>>n>>m;
	
	
	for (int i=0;i<=n+1;i++)
	{
		castle[i][0]=2; 
		castle[i][m+1]=2; 
	}
	for (int i=1;i<=m+1;i++)
	{
		castle[0][i]=2; 
		castle[n+1][i]=2; 
	} //这里把城堡用墙先围上一圈 
	
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
			scanf("%d",&castle[i][j]); //读入 

	int poswall;
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
			if (castle[i][j]!=2)
			{
				poswall=convert(i,j);
				if (castle[i+1][j]==2) //如果(i,j)下方有堵墙 
				{
					add(s,poswall,1);
					add(poswall,s,0); //从超源往这堵墙连边 
					for (int k=i;castle[k][j]!=2;k--) //往上走,记录在wall数组里 
						wall[k][j][0]=poswall;
				}
				if (castle[i][j+1]==2) //如果(i,j)右方有堵墙
				{
					add(poswall+40000,t,1); //竖墙是要加上40000的 
					add(t,poswall+40000,0);
					int poswall=convert(i,j);
					for (int k=j;castle[i][k]!=2;k--)
						wall[i][k][1]=poswall;
				}
			}
	idbegin=cnt; //记录此时的cnt,最终寻找有流边的时候从这里开始找就行了 
	
	for (int i=1;i<=n;i++)
		for (int j=1;j<=m;j++)
			if (castle[i][j]==0) //如果遇到空地,从对应横墙往对应竖墙连边 
			{
				add(wall[i][j][0],wall[i][j][1]+40000,1);
				add(wall[i][j][1]+40000,wall[i][j][0],0);
			}
}

bool bfs() //dinic算法的bfs部分,求出每个点的deep ,如果到不达汇点说明已经满流 
{
	int cur;
	queue <int> q;
	for (int i=0;i<=80001;i++)
		deep[i]=-1;
	deep[s]=0;
	q.push(s);
	while (!q.empty())
	{
		cur=q.front();
		q.pop();
		for (int i=head[cur];~i;i=edge[i].next)
			if (!~deep[edge[i].to] && edge[i].weight)
			{
				deep[edge[i].to]=deep[cur]+1;
				q.push(edge[i].to);
			}
	}
	if (~deep[t])
		return true;
	else
		return false;
}

int dfs(int cur,int limit) //dinic的dfs部分,寻找可行流
{
	if (!limit || cur==t)
		return limit;
		
	int flow=0;
	int f;
	
	for (int i=head[cur];~i;i=edge[i].next)
	{
		if (deep[edge[i].to]==deep[cur]+1 && (f=dfs(edge[i].to,min(limit,edge[i].weight))))
		{
			flow+=f;
			limit-=f;
			edge[i].weight-=f;
			edge[i^1].weight+=f;
			if (!limit) break;
		}
	}
	if (!flow) deep[cur]=-1;
	return flow;
}

int dinic() //能看到这题应该dinic已经掌握了,不再赘述,如不然请先A了模板题 
{
	while (bfs())
		maxflow+=dfs(s,INF);
	return maxflow;
}

int main()
{
	input();
	dinic();
	cout<<maxflow<<endl;
	for (int i=idbegin;i<cnt;i+=2) //扫描所有正向边 
		if (edge[i].weight==0) //如果有流通过,输出对应竖墙的x坐标和横墙的y坐标 
			cout<<(edge[i].to-40000-1)/200+1<<' '<<(edge[i].from-1)%200+1<<endl; //反过来映射的时候要小心 
	return 0;
}

都是评测成功的哈!

记得三连哟!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值