标签:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1537 Accepted Submission(s): 626
4 3 1 1111 1111 1111 LLLL LLLL LLLL 3 2 00000 01110 00000 ..... .LLL. ..... 3 1 00000 01110 00000 ..... .LLL. ..... 5 2 00000000 02000000 00321100 02000000 00000000 ........ ........ ..LLLL.. ........ ........
Case #1: 2 lizards were left behind. Case #2: no lizard was left behind. Case #3: 3 lizards were left behind. Case #4: 1 lizard was left behind.
题意:要你求出在nxm的地图中的蜥蜴尽量逃离之后剩下的最小量,蜥蜴出了地图边缘就算逃离成功,每个柱子如果上面有蜥蜴,那么蜥蜴离开这个柱子的时候柱子高度会减一,高度为0的时候蜥蜴就不能跳到这个上面,每个case输入n和D,D是蜥蜴能跳跃的最大距离,然后是两个n行的地图,因为不知道m大小,所以用%s输入然后计算,地图1中表示柱子的初始高度,地图2中“L”表示这个位置的柱子上有一只蜥蜴
题解:还是老办法,假设原点S和汇点T,每个蜥蜴连接原点S,边权值是1表示一只蜥蜴入场,然后每个高度大于0的柱子全部再设置一个流出点,因为题目中限制流量的是柱子,也就是点,我们把这个点作为这个流量的流入点,再设置一个流出点,连接它们并使边权值为这个点的高度,这样就能把限制从点转移到边了,我是流出点等于流入点加400,因为地图最大的点的数量是400,然后能出边界的且柱子高度大于0的点,全部连接汇点T,边权值是MAX,然后是可以跳跃的柱子之间连接起来,边权值也是MAX,MAX是一个极大值,自己尽量设大点,用来表示这是一条通路就行。
注意:网上各种喊坑:
1、输出那里看好了,英语单词的大考验--!输出的剩余数量如果是no或者1则用单数形式,大于1则用复数形式(单数 lizard was 复数 lizards were);
2、题目说柱子高度d的范围是0<=d<=3,但是有更大的值,也就是说会超过3,这里影响不大,是那些屌丝抱怨着喊出来的;
3、每个高度大于0的柱子作为流入点并额外再设置一个流出点,则柱子与柱子满足跳跃距离是要保证流出点对流入点作边,不然对于这么多代码,混乱一块则让你纠结到死;
4、这里的距离我也不知道作者是怎么想的,竟然是两点的x轴距离加上y轴距离的和;
5、这里对于第一次做这种由点来限制流量的网络流题目,看到别人博客写着“分割点”,尼玛啵什么是分割点又不讲,留下来的就是一堆在你眼里类似乱码的代码,这里我告诉你我的理解,分割点是对于由点来限制流量的情况下把这个点分成两个点,然后相连的这条边就设置为这个点的值,这样这限制流量的就不是点而是边了,这样你学过的那些东东就又能用了,嘿嘿~~~不知道对不对,但是这样理解不会有错。。
对于类似我这种懒于看字的人,我画个图,相信有点用。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define MAX 1000000001
#define Max(a,b) a>b?a:b
#define Min(a,b) a<b?a:b
#define M 1111
using namespace std;
int D,S=0,T,num,cas=1;
char s1[22][22],s2[22][22];//两个地图
struct node
{
int to,val,next;
}s[M*M];
int snum,dnum=400,hand[M],dis[M],q[M];
void setit(int from,int to,int
val)//这个线性建立点的我就不多说了,前面博客有
{
s[snum].to=to;
s[snum].val=val;
s[snum].next=hand[from];
hand[from]=snum++;
s[snum].to=from;
s[snum].val=0;
s[snum].next=hand[to];
hand[to]=snum++;
}
bool pd(int x,int y,int
n,int l)//判断当前坐标移动D之后是否出界
{
if(x<=D||y<=D)return
true;
if(n+1-x<=D||l+1-y<=D)return
true;
return false;
}
bool pddis(int x1,int y1,int
x2,int y2)//判断两坐标的x距离与y距离之和是否小于D,即他们的距离蜥蜴是否能跳跃
{
int a,b;
a=x1-x2;
b=y1-y2;
a=(a>0?a:-a);
b=(b>0?b:-b);
if(a+b<=D)return
true;
return false;
}
bool bfs()//dinic算法中bfs分层,前面博客已经写过详细的了
{
int i,j,k,l,cur,qian,hou;
memset(dis,-1,sizeof(dis));
qian=hou=0;
q[qian++]=S;
dis[S]=0;
while(qian!=hou)
{
cur=q[hou++];
if(hou>=M)hou=0;
for(i=hand[cur];i!=-1;i=s[i].next)
{
k=s[i].to;
if(s[i].val>0&&dis[k]==-1)
{
dis[k]=dis[cur]+1;
q[qian++]=k;
if(qian>=M)qian=0;
if(k==T)return
true;
}
}
}
return false;
}
int dfs(int x,int flow)//同上,前面写过详细的了
{
int i,j,k,l,cost=0;
if(x==T)return flow;
for(i=hand[x];i!=-1;i=s[i].next)
{
k=s[i].to;
if(s[i].val>0&&dis[x]+1==dis[k])
{
l=dfs(k,Min(flow-cost,s[i].val));
if(l>0)
{
cost+=l;
s[i].val-=l;
s[i^1].val+=l;
}else dis[k]=-1;
}
}
return cost;
}
void dinic()//同上
{
int i,j,k,l=num;
while(bfs())
{
k=dfs(S,MAX);
l-=k;
}
if(l==0)printf("Case
#%d: no lizard was left behind.\n",cas++);//这里就是我说的第一个坑点
else printf("Case #%d: %d %s left behind.\n",cas++,l,l==1?"lizard
was":"lizards were");
}
int main (void)
{
int t,n,m,i,j,k,l,x,y,q;
scanf("%d",&t);
while(t--&&scanf("%d%d",&n,&D))
{
snum=0;
num=0;
memset(hand,-1,sizeof(hand));
for(i=0;i<n;i++)
{
scanf("%s",s1[i]);//输入第一个地图
l=strlen(s1[i]);//不好意思,这一句忘记删除了
}
T=1001;
for(i=0;i<n;i++)
{
scanf("%s",s2[i]);输入第二个地图
for(j=0;j<l;j++)
{
q=i*l+j+1;//把地图上的点编号成1到nXm
if(s2[i][j]==‘L‘)
{
num++;
setit(S,q,1);//连接原点S跟当前点
}
if(s1[i][j]!=‘0‘)
{
setit(q,q+dnum,s1[i][j]-‘0‘);//dnum=400,q+dnum是表示q的流出点,而q直接作为流入点
for(k=i*l+j;k>0;k--)
{
x=(k-1)/l;//把编号分解成坐标
y=k-x*l-1;
if(s1[x][y]!=‘0‘&&pddis(i,j,x,y))//判断(x,y)高度和它与(i,j)的距离
{
setit(q+dnum,k,MAX);//两个柱子都能供蜥蜴跳跃且距离可以,则(i,j)流出点连接(x,y)流入点
setit(k+dnum,q,MAX);//(x,y)流出点连接(i,j)流入点
}
}
if(pd(i+1,j+1,n,l))//判断移动D距离能否出界
{
setit(q+dnum,T,MAX);//能出界则当前点的流出点连接汇点T
}
}
}
}
dinic();
}
return 0;
}
照这样每天都有收货的过下去,至少自己更自信~~
HDU--杭电--2732//POJ--2711--Leapin' Lizards--网络流
标签:
原文地址:http://blog.csdn.net/jingdianitnan/article/details/46488571