网络流 HDU2732 && PKU 2711 最大流 SAP

这题目没别的就是TM英语难理解,说什么不好说蜥蜴跳啊跳题目理解了半天,输出TM更BT,还要有单复数之分。哎。。。

题目意思:

是有一些蜥蜴在一个迷宫里面,求这些蜥蜴还有多少是无论如何都逃不出来的。题目只给定一个行数,一个最远能够跳跃的距离,列数是不确定的(题目告知列数小于等于20),但是数据一定会是一个矩阵。每只蜥蜴有一个初始的位置,题目保证这些位置都有一些柱子,每次蜥蜴从一个位置跳到另外一个位置的时候,就会由于反作用力使得一根柱子倒下,你的任务是让尽量多的蜥蜴逃到边界外。每行每列中相邻石柱的距离为1,蜥蜴的跳跃距离是d,即蜥蜴可以跳到平面距离不超过d的任何一个石柱上。
石柱都不稳定,每次当蜥蜴跳跃时,所离开 的石柱高度减1(如果仍然落在地图内部,则到达的石柱高度不变),
如果该石柱原来高度为1,则蜥蜴离开后消失。以后其他蜥蜴不能落脚。任何时刻不能有两只 蜥蜴在同一个石柱上。

还有就是题目说d只会是0-3 又是错的 不信你加个if(d>=4)break; 绝对是错的害我wa了好久真心坑爹。后来去了这一句就ac了。哎。。。太扣条件反而会错呢。

分析:

很显然,这一题,可以用网络流来求解,建图:首先我们要确定一个贪心思想,即如果从某一根柱子能够直接跳到迷宫的外面,那么我们就将这个点连接到汇点,而不用将这个点连接到其他的点了。对于哪些不能跳出去但是又有柱子的点,那么我们就去按照跳跃距离搜寻有没有其他的柱子能够去跳跃,如果能够找到的话,那么连接这两点,并且将容量控制为弧尾节点的柱子数,也正是由于一条弧只能够约束一个顶点,所以我们需要进行拆点,点内之间流量为本身柱子数。题目给定的第二个矩阵其实就是用来确定源点的。该题输入要小心,要符合英语语法~~

步骤:
源点s到每条蜥蜴都连一条容量为1的边
对于每个格子出发,看做一个点,那么这个点能够到达的点和这个点(-)连一条容量无穷的边
由于点有容量的限制,所以把一个点拆成点(-)和点(+),添加 一条容量为点的容量的边,如果某个点可以跳出来,那么就从这个点(+)
向汇点添加一条容量无穷的边,然后最大流即可

最开始做的优化不是很好,看到网上有用数组保存个点的,那样建图比较快,后来那样优化了下就0MS了

我是0做起点 t是r*c*2+1 ISAP做还是比较快的

#include<iostream> 
#include<cstdio> 
#include<cmath>
#include<cstring> 
using namespace std;   
#define MAXN 810 
#define MAXE 30000 
#define INF 0x7fffff      
int ne,nv,tmp,s,t,index;
int dir[40][2]={
               {1,0},{0,-1},{-1,0},{0,1},//4
               {2,0},{1,-1},{0,-2},{-1,-1},{-2,0},{-1,1},{0,2},{1,1},//8
               {3,0},{2,-1},{1,-2},{0,-3},{-1,-2},{-2,-1},{-3,0},{-2,1},{-1,2},{0,3},{1,2},{2,1},//12
               {4,0},{3,-1},{2,-2},{1,-3},{0,-4},{-1,-3},{-2,-2},{-3,-1},{-4,0},{-3,1},{-2,2},{-1,3},{0,4},{1,3},{2,2},{3,1},//16
               }; 
int size[5]={0,4,12,24,40};  
struct Edge{ 
    int next,pair; 
    int v,cap,fLow; 
}edge[MAXE];
int net[MAXN];
int hash[22][22],id;
char gid[22][22],map[22][22];
int getid(int x,int y)
{
    if(hash[x][y]==-1)hash[x][y]=id++;
    return hash[x][y];
} 
bool check(int x,int y,int n,int m)
{
    if(x>=0&&x<n&&y>=0&&y<m)return 1;
    return 0; 
} 
int ISAP() 
{ 
	int numb[MAXN],dist[MAXN],curedge[MAXN],pre[MAXN]; 
 
    int cur_fLow,max_fLow,u,tmp,neck,i; 
    memset(dist,0,sizeof(dist)); 
    memset(numb,0,sizeof(numb)); 
    memset(pre,-1,sizeof(pre)); 
    for(i = 1 ; i <= nv ; ++i) 
        curedge[i] = net[i]; 
    numb[nv] = nv; 
    max_fLow = 0; 
    u = s; 
    while(dist[s] < nv) 
    { 
        if(u == t) 
        { 
            cur_fLow = INF; 
            for(i = s; i != t;i = edge[curedge[i]].v)  
            {   
                if(cur_fLow > edge[curedge[i]].cap) 
                { 
                    neck = i; 
                    cur_fLow = edge[curedge[i]].cap; 
                } 
            } 
            for(i = s; i != t; i = edge[curedge[i]].v) 
            { 
                tmp = curedge[i]; 
                edge[tmp].cap -= cur_fLow; 
                edge[tmp].fLow += cur_fLow; 
                tmp = edge[tmp].pair; 
                edge[tmp].cap += cur_fLow; 
                edge[tmp].fLow -= cur_fLow; 
            } 
            max_fLow += cur_fLow; 
            u = neck; 
        } 
        for(i = curedge[u]; i != -1; i = edge[i].next) 
            if(edge[i].cap > 0 && dist[u] == dist[edge[i].v]+1) 
                break; 
        if(i != -1) 
        { 
            curedge[u] = i; 
            pre[edge[i].v] = u; 
            u = edge[i].v; 
        }else{ 
            if(0 == --numb[dist[u]]) break; 
            curedge[u] = net[u]; 
            for(tmp = nv,i = net[u]; i != -1; i = edge[i].next) 
                if(edge[i].cap > 0) 
                    tmp = tmp<dist[edge[i].v]?tmp:dist[edge[i].v]; 
            dist[u] = tmp + 1; 
            ++numb[dist[u]]; 
            if(u != s) u = pre[u]; 
        } 
    }      
    return max_fLow; 
}
void addedge(int u,int v,int f)
{
	edge[index].next = net[u]; 
    edge[index].v = v; 
    edge[index].cap = f; 
    edge[index].fLow = 0; 
    edge[index].pair = index+1; 
    net[u] = index++; 
    edge[index].next = net[v]; 
    edge[index].v = u; 
    edge[index].cap = 0; 
    edge[index].fLow = 0; 
    edge[index].pair = index-1; 
    net[v] = index++;
	
} 
int main() 
{ 
    int i,j,np,nc,m,n; 
    int a,b,d,k,xx,yy,y; 
    int cases;
    scanf("%d",&cases);
    for(int zz=1;zz<=cases;zz++)
    {
    	scanf("%d%d",&n,&d);
    	if(d>4)break;
    	int lizard=0,r=n,c=0,sum=0;		
		index=0;//index从0开始扫 
        s = 0;  
        memset(net,-1,sizeof(net));
        memset(hash,-1,sizeof(hash));
		memset(gid,0,sizeof(gid));
		memset(map,0,sizeof(map));
		for(i=0;i<n;i++)scanf("%s",gid[i]);
		for(i=0;i<n;i++)scanf("%s",map[i]);
		for(i=0;i<n;i++)
			for(j=0;map[i][j];j++)
			if(map[i][j]=='L')lizard++;
		c=strlen(gid[0]);
		sum=r*c;
		s=0;t=sum+sum+1;
		nv=t+1;
		id=1;//对应点的id 
		/*建图*/
		//连接源点到各个蜥蜴的边
		for(i=0;i<n;i++)
			for(j=0;map[i][j];j++)
			{
				if(map[i][j]=='L')
				addedge(s,getid(i,j),1);
			}
		//连接点与拆点之间的边
		for(i=0;i<n;i++)
			for(j=0;map[i][j];j++)
			{
				if(gid[i][j]>'0')
				addedge(getid(i,j),getid(i,j)+sum,gid[i][j]-'0');
			}
		//连接各个可以跳出去的点到汇点的边和点与点之间的边 
		for(i=0;i<n;i++)
			for(j=0;map[i][j];j++)
			{
				//dir代表每次往外可以调的格子,
				//距离为1跳4个方向,距离2就可以调8个了以此往外跳 
				int temp=getid(i,j)+sum;
				for(k=0;k<size[d];k++)
              	{
					xx=i+dir[k][0];
                  	yy=j+dir[k][1];
                  	if(check(xx,yy,r,c)==0)y=t;
                  	else y=getid(xx,yy);
                  	addedge(temp,y,INF);                                    
            	}
				
			}
		int ans=ISAP();
		lizard-=ans;
		printf("Case #%d: ",zz);
		if(lizard==0)printf("no lizard was left behind.\n");
        else if(lizard==1)printf("%d lizard was left behind.\n",lizard);
        else printf("%d lizards were left behind.\n",lizard); 
 
    } 
    return 0; 
}


 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值