B. Getting Zero
Educational Codeforces Round 126 (Rated for Div. 2) B. Getting Zero
#include<bits/stdc++.h>
using namespace std;
const int N=4e5+10,M=32768;
int dis[N];
void dfs(int k)
{
//if(dis[k]==15) return;
if(k<1) return;
int t;
if(k%2==0)
{
t=k/2;
//t=k/2,dis[t]=min(dis[t],dis[k]+1),dfs(t);
if(dis[t]>dis[k]+1) dis[t]=dis[k]+1,dfs(t);
if(k!=M)
{
t=k+M,t=t/2;//dis[t]=min(dis[t],dis[k]+1),dfs(t);
if(dis[t]>dis[k]+1) dis[t]=dis[k]+1,dfs(t);
}
}
if(dis[k-1]>dis[k]+1) dis[k-1]=dis[k]+1,dfs(k-1);
//t=k-1,dis[t]=min(dis[t],dis[k]+1),dfs(t);
}
void bfs(int k)
{
queue<int> q;
q.push(M);
while(q.size())
{
int k;
int t=q.front();q.pop();
set<int> res;
if(t%2==0) res.insert(t/2),res.insert((t+M)/2);
if(t-1>0) res.insert(t-1);
for(auto x:res)
{
if(dis[x]>dis[t]+1)
{
dis[x]=dis[t]+1;
q.push(x);
}
//dis[x]=min(dis[t]+1,dis[x]);
//q.push(x);
}
}
}
int main()
{
for(int i=1;i<=M;i++) dis[i]=M;
dis[M]=0;
dfs(M);
//bfs(M);
int n;
scanf("%d",&n);
while(n--)
{
int kk;
scanf("%d",&kk);
printf("%d ",dis[kk]);
}
}
这题dfs超时 没有找到解决方法
在bfs中,只有当dis[x]>dis[t]+1时才可以插入到队列中来更新其他答案 ,这样可以节省时间,提高效率,要不然会超时
2
题目链接
题意: 一组数列操作每个减2相邻减1 求得到两个0所需要的最少操作步数。
思路: 分类讨论2个0的位置
1.当2个0间隔大于1时 不会相互影响
2.当2个0间隔为1时会相互影响
3.当两个0相邻时相互影响 每步相当于总数减3 所以答案为(sum+2)/3
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
int a[N],b[N];
int n;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]),b[i]=a[i];
sort(b+1,b+1+n);
int min1=(b[1]+1)/2+(b[2]+1)/2; /这里加一再除2 可以代替 b[1]/2+b[1]%2
//printf("min1=%d\n",min1);
for(int i=1;i<=n-1;i++)
{
if(i==n-1)
{
if(max(a[i],a[i+1])/2<min(a[i],a[i+1])) min1=min(min1,(a[i]+a[i+1]+2)/3);
else min1=min(min1,(max(a[i],a[i+1])+1)/2);
//if(a[i]%2==1&&a[i+2]%2==1) min1=min(min1,a[i]/2+a[i+2]/2+1);
//else min1=min(min1,(a[i]+1)/2+(a[i+2]+1)/2);
}
else
{
if(a[i]%2==1&&a[i+2]%2==1) min1=min(min1,a[i]/2+a[i+2]/2+1);//相隔一个
else min1=min(min1,(a[i]+1)/2+(a[i+2]+1)/2);
if(max(a[i],a[i+1])/2<min(a[i],a[i+1])) min1=min(min1,(a[i]+a[i+1]+2)/3);//两个相邻
else min1=min(min1,(max(a[i],a[i+1])+1)/2);
}
//printf("min1=%d\n",min1);
}
printf("%d\n",min1);
}
3
题目链接
题意: 目标为从左下角移到右上角,每次障碍物会往下降落一个单位,判断目标能否完成
注意: 移动可以有8个选择,不止四个
思路: dfs
#include<bits/stdc++.h>
using namespace std;
char a[10][10];
void dfs(int x,int y,int k)
{
if(k>=7) /这里要多加一个这个 不加会有错误!!!!
{
puts("WIN");
exit(0);
}
for(int i=-1;i<=1;i++) /注意这8个方向的枚举方法
for(int j=-1;j<=1;j++)
{
int xx=x+i,yy=y+j;
if(xx<1||xx>8||yy<1||yy>8) continue;
if(xx-k>=1&&a[xx-k][yy]=='S') continue;
if(xx-k-1>=1&&a[xx-k-1][yy]=='S') continue;
dfs(xx,yy,k+1);
}
}
int main()
{
for(int i=1;i<=8;i++) scanf("%s",a[i]+1);
dfs(8,1,0);
puts("LOSE");
}
我的做法是: 哈哈 爆内存了 这样需要的空间太大了
#include<bits/stdc++.h>
using namespace std;
char a[10][10];
int dx[5]={0,1,0,-1},dy[5]={1,0,-1,0};
int st[1000];
vector <int> res;
const int N=2e6;
//int res[N],be=1,pos=1,sum=1;
int be=1,pos=1,sum=1;
void move(int x,int y)
{
if(a[x][y]=='S') return;
//res(x*8+y);
be++,sum++;
res.push_back(x*8+y);
//res[++pos]=x*8+y;
}
int main()
{
for(int i=1;i<=8;i++) scanf("%s",a[i]+1);
//be=1,pos=1,sum=1;
int stt=1;
res.push_back(65);
for(int cnt=1;cnt<=7;cnt++)
{
int ress=0;
memset(st,0,sizeof st);
for(int i=8;i>=2;i--)
for(int j=1;j<=8;j++)
{
if(a[i-1][j]=='S')
{
a[i-1][j]='.',a[i][j]='S';
st[i*8+j]=1;
//st[i*8+j]=1;
}
}
int k=res.size();
for(int i=0;i<k;i++)
{
sum--;
if(sum<0) break;//<=0 当sum=1的时候减1为0
int xx=res[i]/8,yy=res[i]%8;
if(yy==0) yy=8;
if(st[xx*8+yy]==1)
{
if(yy-1>=1) move(xx,yy-1);
if(yy+1<=8) move(xx,yy+1);
}
else
for(int j=0;j<4;i++)/ 其实没有爆内存 是这里写错了
{
int x=xx+dx[j],y=yy+dy[j];
if(x>=1&&x<=8&&y>=1&&y<=8) move(x,y);
}
}
printf("res.size()=%d\n",res.size());
while((k--)&&res.size()) res.erase(res.begin());
if(sum<=0)
{
stt=0;
break;
}
}
if(stt) puts("WIN");
else puts("LOSE");
}
我的方法应该是把所有方案都列举了出来,而上面的代码是遍历遇到一个成功就返回,所以我的会超时,浪费了很多时间。