目录
- 牧场的安排(猛兽军团2)
- 关灯问题Ⅱ
牧场的安排(猛兽军团2)
猛兽军团1是八向
而这题只有四向
但是这道题有地形限制
所以在求每一行的合法状态时,会发现几乎每行它的合法状态都不同
因此我们就需要新设置一个数组:num用来存储每行合法状态所对应的二进制
值得注意的是:map[i]=(map[i]<<1)+1-x;
这里我们没有把输入的直接存进map里,而是取了反,即1->0,0->1
为啥要取反呢?
因为下面判断一个状态是否合法的时候,是要用到"&"的
这个&,只能看出来是否有重合的1,看不出来0
那就这样,把贫瘠的土地想象成土地上放置有障碍物(盖了房子),表示为1
没盖房子的表示为0
如果一个奶牛的站位和房子重合或者和左移后的另一只奶牛重合
那么这种状态不合法
剩下的就和猛兽军团1差不多了
这个是我自己写的代码,提交AC了
#include<iostream>
using namespace std;
int map[15],sum[15],num[15][250],f[15][250];
int main()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
int x;
cin>>x;
map[i]=(map[i]<<1)+1-x;
}
for(int i=1;i<=n;i++)
for(int j=0;j<(1<<m);j++)
{
if(j&(j<<1)||j&(j>>1)||j&map[i])continue;
sum[i]++;
num[i][sum[i]]=j;
}
num[0][1]=0;
sum[0]=1;
f[0][1]=1;
long long int ans=0;
for(int i=1;i<=n;i++)
for(int j=1;j<=sum[i];j++)
{
int a=num[i][j];
for(int k=1;k<=sum[i-1];k++)
{
int b=num[i-1][k];
if(a&b)continue;
f[i][j]+=f[i-1][k];
}
if(i==n)ans+=f[i][j];
}
cout<<ans%100000000<<"\n";
/* for(int i=1;i<=n;i++)
{
for(int j=1;j<=1<<m;j++)
cout<<f[i][j];
cout<<"\n";
}
for(int i=1;i<=15;i++)cout<<sum[i];*/
return 0;
}
关灯问题Ⅱ
看不懂一点
样例就是先按第二个按钮,把中间那盏灯关上
然后再按第一个按钮,把第一盏灯,第三盏灯关掉
直接放代码吧
#include<bits/stdc++.h>
#define IL inline
#define RI register int
IL void in(int &x)
{
int f=1;x=0;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
x*=f;
}
int a[108][18],f[2048],n,m;
int main()
{
in(n); // cin
in(m);
memset(f,0x3f,sizeof f);
for(RI i=1;i<=m;i++) // 读入
for(RI j=1;j<=n;j++)
in(a[i][j]);
f[(1<<n)-1]=0; // f[s]= 最少次数
//1 表示开着; 0 表示关着;
for(RI i=(1<<n)-1;i>=0;i--) // 枚举所有状态
{
for(RI j=1;j<=m;j++) // 枚举所有开关
{
int now=i;
for(RI l=1;l<=n;l++) // 枚举所有灯泡
{
if(a[j][l]==0) // 如果是0,无论这灯是否开,都不管
continue;
if(a[j][l]==1 && (i&(1<<(l-1)))) // 如果a[i][j]为1,那么当这盏灯开了的时候,把它关上,否则不管
now^=(1<<(l-1)); // now的l位0
//now=i-(1<<(l-1));
if(a[j][l]==-1 && !(i&(1<<(l-1)))) //如果为-1的话,如果这盏灯是关的,那么把它打开,否则也不管
now^=(1<<(l-1)); // now的l位1
}
f[now]=std::min(f[now],f[i]+1); //最少要按几下按钮才能全部关掉
}
}
printf("%d",f[0]==1061109567?-1:f[0]);
}