POJ2331 Water pipe

      题目的大意是,有起点(x1,y1),终点(x2,y2),要铺设从起点到终点的水管,水管的长度分别为L1,L2,L3,L4,水管的数量为C1,C2,C3,C4(管子的种类最多是4),找出铺设水管所需最小的水管总数。

    看到这题首先是DFS,首先计算x方向上所需最小的管子数,然后计算y方向上所需最小的管子数,二者相加便可得最小的水管总数。可是纠结了好几天,编程能力还是太差,只想到了两种剪枝,一种是每种水管在x轴或y轴上只能沿着一个方向,二是判断剩余的水管能不能到达终点,这两种剪枝太弱了,直接是TLE。后来在网上受一个做法的提示:利用每种水管在x轴或y轴上只能沿着一个方向的特点进行枚举。例如,水管L1,在x轴上数目的可能性为-C1,-(C1-1),-(C1-2)···(C1-1),C1,然后进行枚举计算,找到符合要求的最小的数目。那么4种水管最多的可能性是21^4,相对于DFS而言,这已经是非常小的了。

    代码如下:

#include <stdio.h>

#define  abs(x) ((x)>0?(x):-(x))
#define  max_num 0xffff

int cnt;
int l[4],c[4],buffer[4];

void search(int start,int end,int k);
int main()
{
	int x1,y1,x2,y2,k;
	int i,j,result;

	//freopen("test.txt","r",stdin);

    while(scanf("%d %d %d %d %d",&x1,&y1,&x2,&y2,&k)!=EOF)
	{
		cnt=max_num;
		result=0;
		for(i=0;i<k;i++)
			c[i]=buffer[i]=0;

		for(i=0;i<k;i++)
			scanf("%d",&l[i]);
		for(i=0;i<k;i++)
			scanf("%d",&c[i]);

		search(x1,x2,k);
		if(cnt!=max_num)
		{
			result=cnt;
			cnt=max_num;
			for(i=0;i<k;i++)
				c[i]=buffer[i];
			search(y1,y2,k);
		}

		if(cnt!=max_num)
		   printf("%d\n",cnt+result);
		else
			printf("-1\n");
	}
	return 0;
}

void search(int start,int end,int k)
{
	int c1,c2,c3,c4;
	int temp,num;

	for(c1=-1*c[0];c1<=c[0];c1++)
		for(c2=-1*c[1];c2<=c[1];c2++)
			for(c3=-1*c[2];c3<=c[2];c3++)
				for(c4=-1*c[3];c4<=c[3];c4++)
				{
					temp=c1*l[0]+c2*l[1]+c3*l[2]+c4*l[3];
					if(abs(temp)==abs(end-start))
					{
						num=abs(c1)+abs(c2)+abs(c3)+abs(c4);
						if(num<cnt)
						{
							buffer[0]=c[0]-abs(c1);
							buffer[1]=c[1]-abs(c2);
							buffer[2]=c[2]-abs(c3);
							buffer[3]=c[3]-abs(c4);
							cnt=num;
						}
					}
				}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值