家人们!今天又——————————来打卡啦!来看看今天的幸运签吧!
这次的运势还正常点,只是,我不玩我的世界啊!
好了!话不多说,上代码!
#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;
}
都是评测成功的哈!
记得三连哟!