构图的思路与POJ 2391是一样的,对于从一个初级源点s出发的流,如果可到达的点是受限制的,可以先把这些受限制的点都找出来,拆点拆成i->i',然后,s向i'连边,
最后,超级源点S向每个初级源点s连边,每个点i'向汇点连边
为什么要这么做?因为既然从s出发的流是受限制的,我们可以在s上限制它,但也必须在每个s可到的点上限制它,而网络流中是不分这部分流是从哪个源点过来的,因此,无法在下面的点上限制该流,那么,我们必须采取某种策略,使得该流从s出发后不会走到限制范围外的点,方法就是处理出所有受限制的点,直接连边,并且,这些流只能到达汇点
一组不这么做会错的数据
5 1
0YZ52
3Y481
66Y68
Y1665
35923
9YZ89
2Y876
08Y19
Y1891
24689
答案是88,不这么拆点答案就是89,在这里wa了很久
另外,这道题还要预先处理出爆炸点到每个实验室的最短路,以及每个有科学家的实验室到所有具有救生舱的实验室的最短路,如果实验室a到实验室b的最短路径小于等于爆炸点到实验室b的最短路径,就可以连边a->b'
由于边权为1,可以用bfs实现
代码:
#include<iostream>
#include<memory.h>
#include<string>
#include<cstdio>
#include<algorithm>
#include<math.h>
#include<stack>
#include<queue>
#include<vector>
#include<map>
using namespace std;
const int MAX=10005;
const int inf=1<<30;
struct node
{
int u,v,c,next;
}g[MAX*10];
struct Node
{
int x,y,step;
};
int adj[MAX],dis[MAX],cur[MAX],pre[MAX],num[MAX],n,e,s,t,vn,T;
int sx,sy,dir[4][2]={1,0,-1,0,0,1,0,-1};
int flag[15][15],vis[15][15];
char mat1[15][15],mat2[15][15];
bool in(int x,int y)
{
if(x<1||x>n||y<1||y>n)
return false;
return true;
}
void add(int u,int v,int c)
{
g[e].u=u; g[e].v=v; g[e].c=c; g[e].next=adj[u]; adj[u]=e++;
g[e].u=v; g[e].v=u; g[e].c=0; g[e].next=adj[v]; adj[v]=e++;
//if(u==s||v==t)
//if(u==12+n*n&&v==17)
//cout<<u<<" "<<v<<" "<<c<<endl;
}
void bfs1()
{
queue<Node>que;
Node now,next;
now.x=sx; now.y=sy; now.step=0;
que.push(now);
memset(flag,0x7f,sizeof(flag));
memset(vis,0,sizeof(vis));
vis[now.x][now.y]=1;
while(!que.empty())
{
now=que.front();
que.pop();
flag[now.x][now.y]=now.step;
if(now.step>T)
break;
for(int i=0;i<4;i++)
{
int xx=now.x+dir[i][0];
int yy=now.y+dir[i][1];
if(in(xx,yy)&&mat1[xx][yy]!='Y'&&!vis[xx][yy])
{
next.x=xx; next.y=yy; next.step=now.step+1;
vis[xx][yy]=1;
que.push(next);
}
}
}
}
void bfs2(int i,int j)
{
queue<Node>que;
Node now,next;
now.x=i; now.y=j; now.step=0;
que.push(now);
memset(vis,0,sizeof(vis));
vis[now.x][now.y]=1;
while(!que.empty())
{
now=que.front();
que.pop();
if(now.step>T)
break;
if(flag[now.x][now.y]<now.step)
continue;
if(flag[now.x][now.y]==now.step&&(mat2[now.x][now.y]<'1'||mat2[now.x][now.y]>'9'))
continue;
if(mat2[now.x][now.y]>='1'&&mat2[now.x][now.y]<='9')
{
if(now.x!=i||now.y!=j)
add((i-1)*n+j,(now.x-1)*n+now.y+n*n,inf);
if(flag[now.x][now.y]==now.step)
continue;
}
for(int i=0;i<4;i++)
{
int xx=now.x+dir[i][0];
int yy=now.y+dir[i][1];
if(in(xx,yy)&&mat1[xx][yy]!='Y'&&!vis[xx][yy])
{
next.x=xx; next.y=yy; next.step=now.step+1;
vis[xx][yy]=1;
que.push(next);
}
}
}
}
int sap()
{
int i,u,v,flag,aug=inf,flow=0;
for(i=0;i<=vn;i++)
{
cur[i]=adj[i];
num[i]=dis[i]=0;
}
num[0]=vn;
pre[s]=u=s;
while(dis[s]<vn)
{
flag=0;
for(i=cur[u];i!=-1;i=g[i].next)
{
v=g[i].v;
if(g[i].c&&dis[u]==dis[v]+1)
{
flag=1;
aug=min(aug,g[i].c);
pre[v]=u;
cur[u]=i;
u=v;
if(u==t)
{
flow+=aug;
while(u!=s)
{
u=pre[u];
g[cur[u]].c-=aug;
g[cur[u]^1].c+=aug;
}
aug=inf;
}
break;
}
}
if(flag)
continue;
if(--num[dis[u]]==0)
break;
for(dis[u]=vn,i=adj[u];i!=-1;i=g[i].next)
{
v=g[i].v;
if(g[i].c&&dis[v]<dis[u])
{
dis[u]=dis[v];
cur[u]=i;
}
}
dis[u]++;
num[dis[u]]++;
u=pre[u];
}
return flow;
}
int main()
{
int i,j,k;
while(scanf("%d%d",&n,&T)!=EOF)
{
memset(adj,-1,sizeof(adj));
e=0;
s=0;
t=n*n+n*n+1;
vn=t+1;
for(i=1;i<=n;i++)
{
scanf("%s",mat1[i]+1);
for(j=1;j<=n;j++)
{
if(mat1[i][j]>='1'&&mat1[i][j]<='9')
{
add(s,(i-1)*n+j,mat1[i][j]-'0');
}
if(mat1[i][j]=='Z')
{
sx=i;
sy=j;
}
}
}
for(i=1;i<=n;i++)
{
scanf("%s",mat2[i]+1);
for(j=1;j<=n;j++)
{
add((i-1)*n+j,(i-1)*n+j+n*n,inf);
if(mat2[i][j]>='1'&&mat2[i][j]<='9')
add((i-1)*n+j+n*n,t,mat2[i][j]-'0');
}
}
bfs1();
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
if(mat1[i][j]>='1'&&mat1[i][j]<='9')
bfs2(i,j);
}
}
i=1;
printf("%d\n",sap());
/*for(i=1;i<=100;i++)
{
for(j=adj[i];j!=-1;j=g[j].next)
{
if(g[j].v==t)
printf("%d %d\n",i,g[j^1].c);
}
} */
/*for(i=1;i<e;i+=2)
{
if(g[i].u==g[i].v+n*n)
continue;
printf("%d %d %d\n",g[i].v>n*n?g[i].v-n*n:g[i].v,g[i].u>n*n?g[i].u-n*n:g[i].u,g[i].c);
} */
}
return 0;
}