WC 2004 airpig

本文介绍了一种结合双启发函数与随机搜索策略的算法,在特定问题中实现了高效的求解过程。该算法通过定义两个不同的启发函数来指导搜索方向,其中一个考虑了最短路径匹配价值,另一个则关注于在不进行后续操作时最后一个能回到起点的对象所需的时间和无法返回对象的数量。

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

虽然是提交答案的题目,但还是硬着头皮做了一下,想法其实也不是我的,很老很老的某位神犇的题解

这题是一个双启发函数+随机搜索的题,看上去程序应该很慢,实际上竟然最大数据秒解,而且第一次运行就可找到比标准答案优的解,无不让人佩服(我是说佩服写题解的神犇)

贪心的想,每个小猪要飞向猪圈必定找最短路,那么每个小猪向当前所有猪圈连边,km算法最优匹配算权值作为当前操作的启发函数值,但是每一步都做km就会特慢,而且解的优劣也不理想,所以定义另一个启发函数F1表示做了当前操作后若往后不操作的情况下最后一个可以回猪圈的小猪所用时间T加上无论如何都不能回家的小猪个数m的平方的三倍

为什么这么定义函数呢?因为此神犇亲测多数函数后优选出来的。

那么,先计算F1,若F1一样,计算KM,若一样,随机选决策。

我只运行了一次,就有103分,多运行几次就会更优的。

奇丑代码,勿喷

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
typedef int arr[1005];
arr vili,link,vihe,head,vine,next,vitu,turn,vipx,px,vipy,py,vicx,vicy,vifo,foll,lx,ly,pre,slack;
int trap[205][205],w[1005][1005];
int n=0,nop=0,maint=0,tott=0,noc=0;
bool changeflag=0;
int f1[205][10];
bool vx[1005],vy[1005];
bool downdate(int &a,int b)
{
  if (a>b) {a=b;return 1;}
  return 0;
}
void update(int &a,int b)
{
  if (a<b) a=b;
}
void changevi(int l,int t)
{
  int ne=vine[0];
  while (ne)
    {
      if (t==2||t==8)
	{
	  if (vipx[ne]==l)
	    vitu[ne]=t;
	}
      else
	{
	  if (vipy[ne]==l)
	    vitu[ne]=t;
	}
      ne=vine[ne];
    }
}
void changemain(int l,int t)
{
  int ne=next[0];
  while (ne)
    {
      if (t==2||t==8)
	{
	  if (px[ne]==l)
	    turn[ne]=t;
	}
      else
	{
	  if (py[ne]==l)
	    turn[ne]=t;
	}
      ne=next[ne];
    }
}
void movevi(int &nop)
{
  int ne=vine[0],nowp=0,temp=0;
  while (ne)
    {
      if (vitu[ne]==6)
	{
	  vipx[ne]++;
	  if (vipx[ne]>n) vipx[ne]=1;
	  nowp=trap[vipx[ne]][vipy[ne]];
	  if (nowp!=0)
	    if (vifo[0]==nowp||vili[nowp]!=0)
	      {
		nop--;
		vifo[vili[nowp]]=vifo[nowp];
		vili[vifo[nowp]]=vili[nowp];
		vili[nowp]=0;
		vifo[nowp]=0;
		vine[vihe[ne]]=vine[ne];
		vihe[vine[ne]]=vihe[ne];
		temp=vihe[ne];
		vine[ne]=0;
		vihe[ne]=0;
		ne=temp;
	      }
	}
      else
	if (vitu[ne]==4)
	  {
	    vipx[ne]--;
	    if (vipx[ne]<=0) vipx[ne]=n;
	    nowp=trap[vipx[ne]][vipy[ne]];
	    if (nowp!=0)
	      if (vifo[0]==nowp||vili[nowp]!=0)
		{
		  nop--;
		  vifo[vili[nowp]]=vifo[nowp];
		  vili[vifo[nowp]]=vili[nowp];
		  vili[nowp]=0;
		  vifo[nowp]=0;
		  vine[vihe[ne]]=vine[ne];
		  vihe[vine[ne]]=vihe[ne];
		  temp=vihe[ne];
		  vine[ne]=0;
		  vihe[ne]=0;
		  ne=temp;
		}
	  }
	else
	  if (vitu[ne]==8)
	    {  
	      vipy[ne]--;
	      if (vipy[ne]<=0) vipy[ne]=n;
	      nowp=trap[vipx[ne]][vipy[ne]];
	      if (nowp!=0)
		if (vifo[0]==nowp||vili[nowp]!=0)
		  {
		    nop--;
		    vifo[vili[nowp]]=vifo[nowp];
		    vili[vifo[nowp]]=vili[nowp];
		    vili[nowp]=0;
		    vifo[nowp]=0;
		    vine[vihe[ne]]=vine[ne];
		    vihe[vine[ne]]=vihe[ne];
		    temp=vihe[ne];
		    vine[ne]=0;
		    vihe[ne]=0;
		    ne=temp;
		  }
	    }
	  else
	    if (vitu[ne]!=5)
	      {
		vipy[ne]++;
		if (vipy[ne]>n) vipy[ne]=1;
		nowp=trap[vipx[ne]][vipy[ne]];
		if (nowp!=0)
		  if (vifo[0]==nowp||vili[nowp]!=0)
		    {
		      nop--;
		      vifo[vili[nowp]]=vifo[nowp];
		      vili[vifo[nowp]]=vili[nowp];
		      vili[nowp]=0;
		      vifo[nowp]=0;
		      vine[vihe[ne]]=vine[ne];
		      vihe[vine[ne]]=vihe[ne];
		      temp=vihe[ne];
		      vine[ne]=0;
		      vihe[ne]=0;
		      ne=temp;
		    }
	      }
      ne=vine[ne];
    }
}
void movemain(int &nop)
{
  int ne=next[0],nowp=0,temp=0;
  while (ne)
    {
      if (turn[ne]==6)
	{
	  px[ne]++;
	  if (px[ne]>n) px[ne]=1;
	  nowp=trap[px[ne]][py[ne]];
	  if (nowp!=0)
	    if (foll[0]==nowp||link[nowp]!=0)
	      {
		nop--;
		foll[link[nowp]]=foll[nowp];
		link[foll[nowp]]=link[nowp];
		link[nowp]=0;
		foll[nowp]=0;
		next[head[ne]]=next[ne];
		head[next[ne]]=head[ne];
		temp=head[ne];
		next[ne]=0;
		head[ne]=0;
		ne=temp;
		tott+=maint;
	      }
	}
      else
	if (turn[ne]==4)
	  {
	    px[ne]--;
	    if (px[ne]<=0) px[ne]=n;
	    nowp=trap[px[ne]][py[ne]];
	    if (nowp!=0)
	      if (foll[0]==nowp||link[nowp]!=0)
		{
		  nop--;
		  foll[link[nowp]]=foll[nowp];
		  link[foll[nowp]]=link[nowp];
		  link[nowp]=0;
		  foll[nowp]=0;
		  next[head[ne]]=next[ne];
		  head[next[ne]]=head[ne];
		  temp=head[ne];
		  next[ne]=0;
		  head[ne]=0;
		  ne=temp;
		  tott+=maint;
		}
	  }
	else
	  if (turn[ne]==8)
	    {  
	      py[ne]--;
	      if (py[ne]<=0) py[ne]=n;
	      nowp=trap[px[ne]][py[ne]];
	      if (nowp!=0)
		if (foll[0]==nowp||link[nowp]!=0)
		  {
		    nop--;
		    foll[link[nowp]]=foll[nowp];
		    link[foll[nowp]]=link[nowp];
		    link[nowp]=0;
		    foll[nowp]=0;
		    next[head[ne]]=next[ne];
		    head[next[ne]]=head[ne];
		    temp=head[ne];
		    next[ne]=0;
		    head[ne]=0;
		    ne=temp;
		    tott+=maint;
		  }
	    }
	  else
	    if (turn[ne]!=5)
	      {
		py[ne]++;
		if (py[ne]>n) py[ne]=1;
		nowp=trap[px[ne]][py[ne]];
		if (nowp!=0)
		  if (foll[0]==nowp||link[nowp]!=0)
		    {
		      nop--;
		      foll[link[nowp]]=foll[nowp];
		      link[foll[nowp]]=link[nowp];
		      link[nowp]=0;
		      foll[nowp]=0;
		      next[head[ne]]=next[ne];
		      head[next[ne]]=head[ne];
		      temp=head[ne];
		      next[ne]=0;
		      head[ne]=0;
		      ne=temp;
		      tott+=maint;
		    }
	      }
      ne=next[ne];
    }
}
bool find(int x,int n)
{
  if (vx[x]) return 0;
  vx[x]=1;
  int i=0,tmp=0;
  for (i=1;i<=n;i++)
    {
      tmp=lx[x]+ly[i]-w[x][i];
      if (!vy[i] && tmp==0)
	{
	  vy[i]=1;
	  if (pre[i]==0 || find(pre[i],n))
	    {
	      pre[i]=x;
	      return 1;
	    }
	}
      else
	downdate(slack[i],tmp);
    }
  return 0;
}
int km(int n)
{
  int k=0,d=0,i=0,j=0;
  memset(lx,0,sizeof(lx));
  memset(ly,0,sizeof(ly));
  memset(pre,0,sizeof(pre));
  for (i=1;i<=n;i++)
    {
      for (j=1;j<=n;j++)
	update(lx[i],w[i][j]);
    }
  for (k=1;k<=n;k++)
    while (1)
      {
	memset(vx,0,sizeof(vx));
	memset(vy,0,sizeof(vy));
	memset(slack,60,sizeof(slack));
	vx[0]=1;
	if (find(k,n)) break;
	d=400;
	for (i=1;i<=n;i++)
	  if (!vy[i]) downdate(d,slack[i]);
	for (i=1;i<=n;i++)
	  {
	    if (vx[i]) lx[i]-=d;
	    if (vy[i]) ly[i]+=d; else slack[i]-=d;
	  }
      }
  int tot=0;
  for (i=1;i<=n;i++)
    tot+=w[pre[i]][i];
  return tot;
}
void build()
{
  int ne=vine[0],me=0,nowx=0,nowy=0,tmpw=0,tmpx=0,tmpy=0,tmp=0;
  while (ne)
    {
      ++nowx;
      me=vifo[0];
      nowy=0;
      while (me)
	{
	  ++nowy;
	  tmpx=abs(vicx[me]-vipx[ne]);
	  downdate(tmpx,abs(vicx[me]+n-vipx[ne]));
	  downdate(tmpx,abs(-vicx[me]+n+vipx[ne]));
	  tmpy=abs(vicy[me]-vipy[ne]);
	  downdate(tmpy,abs(vicy[me]+n-vipy[ne]));
	  downdate(tmpy,abs(-vicy[me]+n+vipy[ne]));
	  tmpw=tmpx+tmpy;
	  if (vitu[ne]==2)
	    if (vicy[me]>=vipy[ne])
	      tmpw=tmpx+abs(vicy[me]-vipy[ne]);
	    else
	      tmpw=tmpx+abs(n-vipy[ne]+vicy[me]);
	  else
	    if (vitu[ne]==8)
	      if (vicy[me]<=vipy[ne])
		tmpw=tmpx+abs(vicy[me]-vipy[ne]);
	      else
		tmpw=tmpx+abs(n+vipy[ne]-vicy[me]);
	    else
	      if (vitu[ne]==6)
		if (vicx[me]>=vipx[ne])
		  tmpw=tmpy+abs(vicx[me]-vipx[ne]);
		else
		  tmpw=tmpy+abs(n-vipx[ne]+vicx[me]);
	      else
		if (vitu[ne]==4)
		  if (vicx[me]<=vipx[ne])
		    tmpw=tmpy+abs(vipx[ne]-vicx[me]);
		  else
		    tmpw=tmpy+abs(vipx[ne]+n-vicx[me]);
	  w[nowx][nowy]=400-tmpw;
	  me=vifo[me];
	}
      ne=vine[ne];
    }
}
int evaf1(int l,int t)
{
  if (changeflag)
    {
      memcpy(vihe,head,sizeof(head));
      memcpy(vili,link,sizeof(link));
      memcpy(vifo,foll,sizeof(foll));
      memcpy(vine,next,sizeof(next));
    }
  memcpy(vitu,turn,sizeof(turn));
  memcpy(vipx,px,sizeof(px));
  memcpy(vipy,py,sizeof(py));
  changeflag=0;
  int nums=nop,orn=nop,i=0,val=0;
  if (t!=5) changevi(l,t);
  for (i=1;i<=n;i++)
    {
      movevi(nums);
      if (nums<orn)
	{
	  val=i;
	  orn=nums;
	  changeflag=1;
	}
    }
  val+=(3*nums*nums);
  return val;
}
int evaf2(int l,int t)
{
  if (changeflag)
    {
      memcpy(vihe,head,sizeof(head));
      memcpy(vili,link,sizeof(link));
      memcpy(vifo,foll,sizeof(foll));
      memcpy(vine,next,sizeof(next));
    }
  memcpy(vitu,turn,sizeof(turn));
  memcpy(vipx,px,sizeof(px));
  memcpy(vipy,py,sizeof(py));
  changeflag=0;
  if (t!=5) changevi(l,t);
  int nums=nop;
  movevi(nums);
  if (nums<nop) changeflag=1;
  build();
  return km(nums);
}
void print(int dec1,int dec2)
{
  if (dec2==5)
    printf("X0");
  else
    if (dec2==2)
      printf("S%d",dec1-1);
    else
      if (dec2==8)
	printf("N%d",dec1-1);
      else
	if (dec2==4)
	  printf("W%d",dec1-1);
	else
	  printf("E%d",dec1-1);
  printf("\n");
}
int main(int argc,char* argv[])
{
  char inname[200],outname[200];
  srand((unsigned)time(NULL));
  sprintf(inname,"airpig%s.in",argv[1]);
  sprintf(outname,"airpig%s.out",argv[1]);
  freopen(inname,"r",stdin);
  freopen(outname,"w",stdout);
  int i=0,j=0;
  scanf("%d",&n);
  printf("%d\n",n);
  scanf("%d\n",&n);
  char tmpc=0;
  for (i=1;i<=n;i++)
    {
      for (j=1;j<=n;j++)
	{
	  tmpc=getchar();
	  if (tmpc!='*'&&tmpc!='.')
	    {
	      nop++;
	      head[nop]=nop-1;
	      next[nop-1]=nop;
	      px[nop]=j;
	      py[nop]=i;
	      turn[nop]=(int)(tmpc-'0');
	    }
	  else
	    if (tmpc=='*')
	      {
		noc++;
		link[noc]=noc-1;
		foll[noc-1]=noc;
		vicx[noc]=j;
		vicy[noc]=i;
		trap[j][i]=noc;
	      }
	}
      scanf("\n");
    }
  int ans1=0,ans2=0,dec1=0,dec2=0,tmp=0;
  while (nop)
    {
      changeflag=1;
      ans1=evaf1(0,5);
      ans2=200000000;
      dec1=0;
      dec2=5;
      for (i=1;i<=n;i++)
	{
	  f1[i][2]=evaf1(i,2);
	  f1[i][8]=evaf1(i,8);
	  f1[i][4]=evaf1(i,4);
	  f1[i][6]=evaf1(i,6);
	  if (downdate(ans1,f1[i][2]))
	    {
	      dec1=i;
	      dec2=2;
	    }
	  if (downdate(ans1,f1[i][8]))
	    {
	      dec1=i;
	      dec2=8;
	    }
	  if (downdate(ans1,f1[i][4]))
	    {
	      dec1=i;
	      dec2=4;
	    }
	  if (downdate(ans1,f1[i][6]))
	    {
	      dec1=i;
	      dec2=6;
	    }
	}//选最优的ans1
      changeflag=1;
      ans2=evaf2(dec1,dec2);//计算当前决策的f2,注意dec2=5时的情况
      for (i=1;i<=n;i++)
	{
	  if (ans1==f1[i][2] &&(dec1!=i || dec2!=2))
	    {
	      tmp=evaf2(i,2);
	      if (tmp>ans2)
		{
		  ans2=tmp;
		  dec1=i;
		  dec2=2;
		}
	      else
		if (tmp==ans2 &&(rand()&1))
		  {
		    ans2=tmp;
		    dec1=i;
		    dec2=2;
		  }
	    }
	  if (ans1==f1[i][8] &&(dec1!=i || dec2!=8))
	    {
	      tmp=evaf2(i,8);
	      if (tmp>ans2)
		{
		  ans2=tmp;
		  dec1=i;
		  dec2=8;
		}
	      else
		if (tmp==ans2 &&(rand()&1))
		  {
		    ans2=tmp;
		    dec1=i;
		    dec2=8;
		  }
	    }
	  if (ans1==f1[i][4] &&(dec1!=i || dec2!=4))
	    {
	      tmp=evaf2(i,4);
	      if (tmp>ans2)
		{
		  ans2=tmp;
		  dec1=i;
		  dec2=4;
		}
	      else
		if (tmp==ans2 &&(rand()&1))
		  {
		    ans2=tmp;
		    dec1=i;
		    dec2=4;
		  }
	    }
	  if (ans1==f1[i][6] &&(dec1!=i || dec2!=6))
	    {
	      tmp=evaf2(i,6);
	      if (tmp>ans2)
		{
		  ans2=tmp;
		  dec1=i;
		  dec2=6;
		}
	      else
		if (tmp==ans2 &&(rand()&1))
		  {
		    ans2=tmp;
		    dec1=i;
		    dec2=6;
		  }
	    }
	}//选最优的ans2
      if (dec2!=5) changemain(dec1,dec2);//按决策改变原图中的小猪的转向,注意dec2==5的情况
      maint++;
      movemain(nop);//按当前状态运行一步
      print(dec1,dec2);//打印决策
    }
  printf("%d %d",maint,tott);
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值