状态压缩.种花小游戏

HLUOJ486. 种花小游戏

状压经典的例题

题目描述

植物大战僵尸这款游戏中,还有个特别有意思的赚钱方式——种花(能长金币的花)。 种出来的金币需要玩家点击才能得到,或者,玩家可以购买一只蜗牛来帮助捡金币。然而,蜗牛爬得
慢是众所周知的。所以,场上有若干金币时,蜗牛总是喜欢以最少的行程来捡走所有的金币。 现在告诉你场上n个金币所在位置的坐标,以及蜗牛所在位置,让你求出蜗牛捡走所有金币的最小行程。

输入格式

第一行一个正整数n,表示金币数量 之后n行,每行两个非负整数x、y,分别表示金币所在位置坐标 最后一行两个正整数x、y表示蜗牛起始位置。

输出格式

一个实数(保留2位小数),表示最短行程
这题就简单的状压,然而由于一个巨坑卡了两个小时,到最后才发现了一个问题。

if((zh&mi(i-1,1))==0) continue;

一开始这句话zh&mi(i-1,1)两边没加括号,然后它居然先算的是mi(i-1,1)==0,得到布尔值再与zh进行&运算,于是我调了1个小时找各种错误。
代码如下:
#include<bits/stdc++.h>
using namespace std;
int x[20],y[20],xs,ys,n,k;
double s[20][20],f[68000][30];
int mi(int num,int sum)
{
if(num==0) return sum;
sum*=2;num--;
return mi(num,sum);
}
int read()
{
bool flag=true;
int num=0;char c=getchar();
for(;c<'0'||c>'9';c=getchar())if(c=='-') flag=false;
for(;c>='0'&&c<='9';c=getchar())
num=(num<<3)+(num<<1)+c-48;
if(flag) return num;
else return -num;
}
void init()
{
n=read();
for(int i=1;i<=n;++i)
x[i]=read(),y[i]=read();
xs=read(),ys=read();
x[0]=xs;y[0]=ys;
for(int i=1;i<=n;++i)for(int j=1;j<=n;++j) s[i][j]=2000000000.0;
for(int i=0;i<=n;++i)
for(int j=i;j<=n;++j)
s[i][j]=s[j][i]=sqrt( (x[i]-x[j])*(x[i]-x[j]) + (y[i]-y[j])*(y[i]-y[j]) );
k=mi(n,1);k--;
return;
}
void dp(int zh,int pl)
{
for(int i=1;i<=n;++i)
{
if((zh&mi(i-1,1))==0) continue;
if(f[zh-mi(i-1,1)][i]==1689000000.0) {dp(zh-mi(i-1,1),i);f[zh][pl]=min(f[zh][pl],f[zh-mi(i-1,1)][i]+s[i][pl]);}
else f[zh][pl]=min(f[zh][pl],f[zh-mi(i-1,1)][i]+s[i][pl]);
}
}
int main()
{
init();
for(int i=0;i<=k;++i) for(int j=1;j<=n;++j) f[i][j]=1689000000.0;
for(int i=1;i<=n;++i) f[0][i]=s[0][i];
double ans=2000000000.0;
for(int i=1;i<=n;++i) dp(k-mi(i-1,1),i),ans=min(ans,f[k-mi(i-1,1)][i]);
printf("%.2lf",ans);
return 0;
}

以后还是要注意运算顺序啊。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,下面是一个简单的状态机设计,实现一个流水灯: 首先需要定义两种花型,这里假设为正向和反向两种花型。 状态1(正向1):开启第1个灯,关闭其他灯。 状态2(正向2):开启第1和第2个灯,关闭其他灯。 状态3(正向3):开启第1、2、3个灯,关闭其他灯。 状态4(正向4):开启第1、2、3、4个灯,关闭其他灯。 状态5(反向1):开启第8个灯,关闭其他灯。 状态6(反向2):开启第7和第8个灯,关闭其他灯。 状态7(反向3):开启第6、7、8个灯,关闭其他灯。 状态8(反向4):开启第5、6、7、8个灯,关闭其他灯。 在状态1到状态4之间,状态之间的转换周期为0.5Hz;在状态5到状态8之间,状态之间的转换周期为2Hz。 状态机的实现可以采用计数器来实现。假设计数器的频率为4MHz,则在状态1到状态4之间,计数器需要每8个时钟周期增加1;在状态5到状态8之间,计数器需要每2000个时钟周期增加1。 具体实现可以参考下面的伪代码: ``` // 定义状态 typedef enum { STATE_1, STATE_2, STATE_3, STATE_4, STATE_5, STATE_6, STATE_7, STATE_8 } state_t; // 定义计数器 volatile uint32_t counter = 0; // 定义当前状态 volatile state_t current_state = STATE_1; void interrupt_handler() { // 计数器自增 counter++; // 根据当前状态进行相应的操作 switch(current_state) { case STATE_1: // 控制灯的开关状态 // ... // 判断是否需要转换到下一个状态 if(counter == 8) { counter = 0; current_state = STATE_2; } break; case STATE_2: // 控制灯的开关状态 // ... // 判断是否需要转换到下一个状态 if(counter == 8) { counter = 0; current_state = STATE_3; } break; case STATE_3: // 控制灯的开关状态 // ... // 判断是否需要转换到下一个状态 if(counter == 8) { counter = 0; current_state = STATE_4; } break; case STATE_4: // 控制灯的开关状态 // ... // 判断是否需要转换到下一个状态 if(counter == 8) { counter = 0; current_state = STATE_5; } break; case STATE_5: // 控制灯的开关状态 // ... // 判断是否需要转换到下一个状态 if(counter == 2000) { counter = 0; current_state = STATE_6; } break; case STATE_6: // 控制灯的开关状态 // ... // 判断是否需要转换到下一个状态 if(counter == 2000) { counter = 0; current_state = STATE_7; } break; case STATE_7: // 控制灯的开关状态 // ... // 判断是否需要转换到下一个状态 if(counter == 2000) { counter = 0; current_state = STATE_8; } break; case STATE_8: // 控制灯的开关状态 // ... // 判断是否需要转换到下一个状态 if(counter == 2000) { counter = 0; current_state = STATE_1; } break; } } ``` 在上面的代码断处理函数用来实现流水灯的控制。根据当前状态和计数器的值,控制相应的灯的开关状态,并在需要转换到下一个状态时更新当前状态。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值