uva 10123 - No Tipping

本文解析了一段在UVA竞赛中取得优异成绩的代码,介绍了其核心思路:通过中间放置、力矩排序及搜索加剪枝的方法高效解决问题,并详细解释了关键代码段的作用及其背后的逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原题

下面的代码跑得很快,让我一不小心进入了uva前二十的光荣榜。但是假若我不说我这代码是参考大牛的,我会相当羞愧。大牛

另外,思路是这样的:

先放中间;

再把两侧的分一下类,按力矩大小排序

左边试放一下,右边试放一下。

某种情况下,这个木块一定要现在放。

搜索+剪枝。

剪枝巧妙地令程序跑起来脱离地面。

                vis[k]=true;
  int &d=P[k].d,&w=P[k].w;
  nleft=left+(d+3)*w;nright=right+(3-d)*w;
  if(nright>=0) tright=0;
  if(nleft>=0 && nright>=0)
  {
  A[cur]=k;
flag=dfs(nleft,nright,cur+1);

  if(flag==2) return 2;
  if(flag==-1) break;
  }
  vis[k]=false;

这段代码尤为关键。

看看vis[k]标记的位置。

超时的做法:

  int &d=P[k].d,&w=P[k].w;
  nleft=left+(d+3)*w;nright=right+(3-d)*w;
  if(nright>=0) tright=0;
  if(nleft>=0 && nright>=0)
  {
  A[cur]=k;

  vis[k]=true;
flag=dfs(nleft,nright,cur+1); 
vis[k]=false;
  if(flag==2) return 2;
  if(flag==-1) break;
  }
为什么?

因为当flag==-1时,意味着下一层,左边不能放,右边能放。左边不能放,是因为放不下,力矩太打了,因为力矩是经过排序的,下一层的力矩都放不下了,那么这层的这个木块一定要选。反证法证明之。假如不选,那么左边还没有选完,必然要选左边还未放的木块放上去,因为目前这个木块的力矩是最小的,如果这个木块都不选,后面的木块更不用说了,换一个说法就是,not to mention the rest objucts.

巧妙之处:

扩大一倍,将小数变为整数。

排序,为剪枝铺垫。

先放中间的优势策略。

回溯时,将下层的摆放方法传递到这层供剪枝。

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

int left,right,n,A[25],L[25],R[25],n1,n2;
bool vis[25];

struct Pack
{
    int w,d;
} P[25];

int dfs(int left,int right,int cur)
{
	if(cur==n) return 2;
	int nleft,nright,tleft=1,tright=1,i,flag,k;
	for(i=0;i<n1;i++)
	{
	  k=L[i];
	  if(!vis[k])
	  {
	  	vis[k]=true;
	  	int &d=P[k].d,&w=P[k].w;
  		nleft=left+(d+3)*w;nright=right+(3-d)*w;
  		if(nleft>=0) tleft=0;
  		if(nleft>=0 && nright>=0)
  		{
  			A[cur]=k;
			flag=dfs(nleft,nright,cur+1);	 	
			if(flag==2)  return 2;
			if(flag==1)  break;
	  	}
	  	vis[k]=false;
	  }
	}
  	for(i=0;i<n2;i++)  
  	{
	  k=R[i];
	  if(!vis[k])
  	  {
  	  	vis[k]=true;
	  	int &d=P[k].d,&w=P[k].w;
	  	nleft=left+(d+3)*w;nright=right+(3-d)*w;
	  	if(nright>=0) tright=0;
	  	if(nleft>=0 && nright>=0)
	  	{
	  		A[cur]=k;
			flag=dfs(nleft,nright,cur+1);	 	
			
	  		if(flag==2) return 2;
	  		if(flag==-1) break;
	  	}
	  	vis[k]=false;
 	  }
  	}
 	return tleft-tright;
}

int torque(int i)
{
    if(P[i].d<0)
      return (-3-P[i].d)*P[i].w;
    else return(P[i].d-3)*P[i].w;
}

void swap(int *a,int *b)
{
    int t=*a;*a=*b;*b=t;
}

void Qsort(int *A,int start,int end)
{
    int i=start,j=end,m=torque(A[start]);
    do
    {
        while(torque(A[i])<m) i++;
        while(torque(A[j])>m) j--;
        if(i<=j)
        {
            swap(&A[i],&A[j]);
            i++;
            j--;
        }
    }while(i<=j);
    if(i<end) Qsort(A,i,end);
    if(j>start) Qsort(A,start,j);
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("10123.txt","r",stdin);
#endif
    int len,w,N=0;
    while(scanf("%d%d%d",&len,&w,&n)==3 &&(len || w || n))
    {
        left=right=3*w;
        int i;
        for(i=0; i<n; i++)
        {
            scanf("%d%d",&P[i].d,&P[i].w);
            P[i].d*=2;
        }
        printf("Case %d:\n",++N);
        memset(vis,0,sizeof(vis));
        int cur=0;
        for(i=0;i<n;i++)
        {
        	if(P[i].d<=3 && P[i].d>=-3)
        	{
        		left+=(P[i].d+3)*P[i].w;
        		right+=(3-P[i].d)*P[i].w;
	        	vis[i]=true;
	        	A[cur++]=i;
	        }
        }
        n1=n2=0;
        for(i=0;i<n;i++) if(!vis[i])
        {
        	if(P[i].d<0) L[n1++]=i;
        	else R[n2++]=i;
        }
        Qsort(L,0,n1-1);
        Qsort(R,0,n2-1);
        if(dfs(left,right,cur)==2)
        {
        	for(i=n-1;i>=0;i--)  printf("%d %d\n",P[A[i]].d/2,P[A[i]].w);
        }else printf("Impossible\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值