记得这是当时我好几个月前才进入特训小组时的题目,。。。现在才想起来全都补掉…
kuangbin的专题确实好啊,以后一周给自己额外加一套专题来写
A . POJ 1321棋盘问题
基础的dfs递归求解,
先标记下vis数组来储存已经使用过哪些列数
之后可以遍历每一行,在这一行中找到符合条件的列数
(为棋子且这一列没用过)
之后再递归寻找下一行,
递归的边界是目前获得的棋子数目达到了要求或者行数超过了n
边界
if(cnt==k)///数目符合条件
{
ans++;
cnt=0;
return ;
}
if(line>n)///超过了行数
{
return ;
}
注意回溯就好了
void dfs(int line,int cnt)
{
if(cnt==k)
{
ans++;
cnt=0;
return ;
}
if(line>n)
{
return ;
}
rep(i,1,n)
{
if(vis[i]||str[line][i]=='.')
continue;
vis[i]=1;
dfs(line+1,cnt+1);
vis[i]=0;
}
dfs(line+1,cnt);///记得加这一个!!
///当前行全都不符合就直接进入下一行
}
变量含义是line代表当前遍历到了哪一行,cnt代表已经找到了多少个棋子
ans是总的方案数目
B . POJ 2251 Dungeon Master
题目意思是给出你x,y,z代表地牢的三维大小,同时给出S为起始点,E为终点,一次可以上下左右前后移动一格,消耗一分钟,求问逃出地牢的最短时间,若无法逃出地牢就输出“trapped”
bfs的基础题目,完全是模板题,没啥好说的…用STL的队列写会更好
void bfs(int nx,int ny,int nz)
{
queue<node>que;
node now;
now.x=nx;
now.y=ny;
now.z=nz;
now.s=0;
que.push(now);
vis[nx][ny][nz]=1;
while(!que.empty())
{
now=que.front();
que.pop();
rep(i,0,5)
{
int tx=now.x+xx[i];
int ty=now.y+yy[i];
int tz=now.z+zz[i];
if(tx<1||tx>l||ty<1||ty>r||tz<1||tz>c)
continue;
if(vis[tx][ty][tz]||mp[tx][ty][tz]=='#')
continue;
vis[tx][ty][tz]=1;
node nxt;
nxt.x=tx;
nxt.y=ty;
nxt.z=tz;
nxt.s=now.s+1;
que.push(nxt);
if(mp[tx][ty][tz]=='E')
{
f=1;
ans=nxt.s;
return ;
}
}
}
}
C . POJ 3278 Catch That Cow
给出起点和终点,每次移动可以使当前x变成x-1或者x+1,或者2x,求出最小移动次数
简单的bfs,每次可以扩展到x-1,x+1,2x三种地方直接放进队列就可以了,但是直接写的话会超时,需要约束一下范围,小于0以及大于最大值的就不要放进队列了
这题我的代码写的有点丑了。。。
int main()
{
int n,k;
while(~scanf("%d %d",&n,&k))
{
ms(vis,0);
vis[n]=1;
queue<node>que;
node now;
now.pos=n;
now.step=0;
que.push(now);
while(!que.empty())
{
now=que.front();
if(now.pos==k)
{
printf("%d\n",now.step);
break;
}
que.pop();
node nxt;
nxt.step=now.step+1;
nxt.pos=now.pos+1;
if(nxt.pos>=0&&nxt.pos<maxn){
if(!vis[nxt.pos]){
que.push(nxt);
vis[nxt.pos]=1;
}
}
nxt.pos=now.pos-1;
if(nxt.pos>=0&&nxt.pos<maxn){
if(!vis[nxt.pos]){
que.push(nxt);
vis[nxt.pos]=1;
}
}
nxt.pos=now.pos*2;
if(nxt.pos>=0&&nxt.pos<maxn){
if(!vis[nxt.pos]){
que.push(nxt);
vis[nxt.pos]=1;
}
}
}
}
return 0;
}
D . POJ 3279 Fliptile
大概意思是给出一个二维数组,每次反转可以使这个数从1变成0
或者从0变成1,但一个位置在反转时它也会顺带着使它上下左右四个数一起反转,求出最小反转的次数,在次数相同的情况下找出字典序最小的
这题查题解才明白的,首先就是理解为二进制来模拟第一行的反转情况,之后整体的就确定了,因为当你第一行的反转情况确定了之后,那你这一行的的为1的地方就只能靠下一行列数相对的地方来反转了,之后下一行又确定了下下一行的反转,最后只需要check最后一行是否全为0就可以了(因为最后一行后面没有了。。)
所以我们枚举的第一行的反转就可以了,对于每一种第一行的反转且可以全为0的方案,我们取反转次数最小的,从小到大枚举且用小于号来处理就可以顺带解决了字典序最小的问题
我们先开四个数组
int mp[20][20],ans[20][20],tmp[20][20],pic[20][20];
分别表示,最初的图形,最后的答案,每次更新的答案,每次复制过去的图形
我们先枚举第一行的反转状态
int ed=(1<<m)-1;
rep(i,0,ed)
这样就可以利用二进制下每一位是0还是1来模拟第一行的每一列是否要反转
rep(i,0,ed)
{
memcpy(pic,mp,sizeof(mp));
cnt=0;
ms(tmp,0);
int val=i;
per(j,m,1)
{
根据状态来给第一行翻转的情况赋值
if(val&1)
{
tmp[1][j]=1;
}
val>>=1;
}
if(check()&&(num==-1||num>cnt))这里不要等于号来确保字典序最小
{
num=cnt;
memcpy(ans,tmp,sizeof(tmp));///复制tmp到ans里面
}
}
关于check函数的书写
bool check()
{
首先对于第一行的状态来翻转一下第一行
rep(i,1,m)
{
if(tmp[1][i])
{
filp(1,i);
tmp[1][i]=1;
}
}
之后枚举后面的行查找每个位置它的上面是否为1
是的话就反转这个位置
rep(i,2,n)
{
rep(j,1,m)
{
if(pic[i-1][j])
{
filp(i,j);
tmp[i][j]=1;
}
}
}
遍历最后一行状态是否全为0来判断是否可行
rep(i,1,m)
{
if(pic[n][i])
return false;
}
可行的话就统计翻转了几次
rep(i,1,n)
{
rep(j,1,m)
{
cnt+=tmp[i][j];
}
}
return true;
}
AC代码是
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<vector>
#include<utility>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define ms(arr,x) memset(arr,x,sizeof(arr))
#define IOS ios::sync_with_stdio(false),cin.tie(NULL)
#define eps 1e-4
#define endl '\n'
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define ll long long
#define ls rt<<1
#define rs rt<<1|1
#define md (l+r>>1)
#define MP make_pair
using namespace std;
typedef pair<int,int> pii;
inline int read()
{
int sign=1,ans=0;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
sign=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
ans=ans*10+(ch-'0');
ch=getchar();
}
return sign*ans;
}
const ll mod=1e9+7;
const int maxn=1e5+5;
const double PI=acos(-1.0);
int mp[20][20],ans[20][20],tmp[20][20],pic[20][20];
int n,m,num,cnt;
int nx[5][2]={0,0,0,1,0,-1,1,0,-1,0};
void filp(int x,int y)
{
rep(i,0,4)
{
pic[x+nx[i][0]][y+nx[i][1]]=1-pic[x+nx[i][0]][y+nx[i][1]];
}
}
bool check()
{
rep(i,1,m)
{
if(tmp[1][i])
{
filp(1,i);
tmp[1][i]=1;
}
}
rep(i,2,n)
{
rep(j,1,m)
{
if(pic[i-1][j])
{
filp(i,j);
tmp[i][j]=1;
}
}
}
rep(i,1,m)
{
if(pic[n][i])
return false;
}
rep(i,1,n)
{
rep(j,1,m)
{
cnt+=tmp[i][j];
}
}
return true;
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
ms(mp,0),ms(ans,0);
rep(i,1,n)
{
rep(j,1,m)
{
mp[i][j]=read();
}
}
num=-1;
int ed=(1<<m)-1;
rep(i,0,ed)
{
memcpy(pic,mp,sizeof(mp));
cnt=0;
ms(tmp,0);
int val=i;
per(j,m,1)
{
if(val&1)
{
tmp[1][j]=1;
}
val>>=1;
}
if(check()&&(num==-1||num>cnt))
{
num=cnt;
memcpy(ans,tmp,sizeof(tmp));///复制tmp到ans里面
}
}
if(num==-1)
{
printf("IMPOSSIBLE\n");
}
else
{
rep(i,1,n)
{
rep(j,1,m-1)
{
printf("%d ",ans[i][j]);
}
printf("%d\n",ans[i][m]);
}
}
}
return 0;
}
关于memcpy复制数组这个函数,学到了~
先停了,明天继续更新这个帖子
-----------------------------------
咳咳,继续更新
E . POJ 1426 Find The Multiple
大致意思是给出一个数 求出一个数每一位仅由0or1构成且为给出的数的倍数,即给出n,求出一个m使得m%n为0且m的每一位要么是0要么是1
这题好像要用到什么同余模定理…但是数据比较水longlong范围内就可以了…那个定理我还不会…
因为是仅有0和1 所以我们直接枚举每一位,dfs两个接口,要么下一位是0要么下一位是1,所以接口是dfs(n10+0),dfs(n10+1),数据不行,所以在19位以内就会有结果了…迷迷糊糊的ac了,,
ll ans,n;
void dfs(ll now,ll num)
{
if(num>19||flag)
{
return ;
}
if(now%n==0)
{
flag=1;
ans=now;
return ;
}
dfs(now*10,num+1);
dfs(now*10+1,num+1);
}
int main()
{
while(~scanf("%lld",&n))
{
if(n==0)
break;
flag=0;
dfs(1,1);
printf("%lld\n",ans);
}
#ifdef _LOCALE_DEBUG_PAUSE
system("pause");
#endif //_LOCALE_DEBUGE_PAUSE
return 0;
}
F . POJ Prime Path
题目意思是给出起始数和结尾数,每次可以改变某一位的数字变为0-9任意一个,但要求变换过程中的每一个数都必须是质数,
一共四位,每一位可以0-9所以直接暴力搜索就OK了~~
bfs每一位数字的可能改变(必须要改变后还是质数)就好了
记得打个素数表以免超时…顺便复习下埃氏筛法
int a,b,flag,ans,vis[maxn],prime[maxn];
struct node
{
int val;
int step;
};
void ESS()埃氏筛法 筛选n以内的所有素数
{
rep(i,1,10000)
{
prime[i]=1;
}
prime[0]=prime[1]=0;
int cup[maxn],pos=0;
rep(i,2,10000)
{
if(prime[i])
{
cup[++pos]=i;
}
for(int j=1;j<=pos&&i*cup[j]<=10000;j++)
{
prime[i*cup[j]]=0;
if(i%cup[j]==0)///如果前面已经除过
break;
}
}
}
void bfs()
{
queue<node>que;
node now;
now.val=a;
now.step=0;
que.push(now);
while(!que.empty())
{
now=que.front();
que.pop();
int val=now.val;
vis[val]=1;
if(val==b)
{
ans=now.step;
flag=1;
return ;
}
int a1,a2,a3,a4,tmp;
node nxt;
a1=val/1000,a2=val/100%10,a3=val/10%10,a4=val%10;
for(a1=1;a1<=9;a1++)
{
tmp=a1*1000+a2*100+a3*10+a4;
if(prime[tmp]&&!vis[tmp])
{
nxt.val=tmp;
nxt.step=now.step+1;
que.push(nxt);
}
}
a1=val/1000,a2=val/100%10,a3=val/10%10,a4=val%10;
for(a2=0;a2<=9;a2++)
{
tmp=a1*1000+a2*100+a3*10+a4;
if(prime[tmp]&&!vis[tmp])
{
nxt.val=tmp;
nxt.step=now.step+1;
que.push(nxt);
}
}
a1=val/1000,a2=val/100%10,a3=val/10%10,a4=val%10;
for(a3=0;a3<=9;a3++)
{
tmp=a1*1000+a2*100+a3*10+a4;
if(prime[tmp]&&!vis[tmp])
{
nxt.val=tmp;
nxt.step=now.step+1;
que.push(nxt);
}
}
a1=val/1000,a2=val/100%10,a3=val/10%10,a4=val%10;
for(a4=0;a4<=9;a4++)
{
tmp=a1*1000+a2*100+a3*10+a4;
if(prime[tmp]&&!vis[tmp])
{
nxt.val=tmp;
nxt.step=now.step+1;
que.push(nxt);
}
}
}
return ;
}
void solve()
{
ms(vis,0);
a=read(),b=read();
flag=0;
bfs();
if(flag)
{
printf("%d\n",ans);
}
else
{
printf("Impossible\n");
}
}
G . POJ 3087 Shuffle’m Up
题意第一时间没读明白…
给出两个字符串,请问是否可以合成出题目要求的结果
合成方式是
你可以理解为一个string类,先加上第二个字符串的第一个,再加上第一个字符串的第一个,再加上第二个字符串的第二个
分割是前一半是第一个,后一半是第二个 弄明白方式就好写了,这样结合一定会是一个循环,当你某一个合成的字符串已经出现过的话就跳出吧,用一个map来记录字符串出现的次数
void solve()
{
int len;cin>>len;
string a,b,c;
cin>>a>>b>>c;
map<string,int>mp;
queue<node>que;
string tmp;
int n1=0,n2=0;
rep(i,0,len*2-1)
{
if(i&1)
{
tmp+=a[n2++];
}
else
{
tmp+=b[n1++];
}
}
node now;
now.tmp=tmp;
now.step=1;
que.push(now);
while(!que.empty())
{
tmp=a=b="";
n1=n2=0;
now=que.front();
que.pop();
if(now.tmp==c)
{
cout<<++cas<<" "<<now.step<<endl;
return ;
}
rep(i,0,len*2-1)
{
if(i<len)
{
a+=now.tmp[i];
}
else
{
b+=now.tmp[i];
}
}
rep(i,0,len*2-1)
{
if(i&1)
{
tmp+=a[n2++];
}
else
{
tmp+=b[n1++];
}
}
if(mp[tmp]==0)
{
mp[tmp]=1;
node nxt;
nxt.tmp=tmp;
nxt.step=now.step+1;
que.push(nxt);
}
else
{
break;
}
}
cout<<++cas<<" -1"<<endl;
}
H . POJ 3414 Pots
给出两个杯子没有刻度,只有大小,可以加满任意一个,或者全倒完,或者加其中一个到另一个上面,
这是一个好题目!!我在这里不仅学到了倒水问题怎么用bfs写,还学会了记录路径的新办法! 后面那道迷宫的题目就借用了这里记录路径的方法
依然是bfs,但是我们每次bfs的时候我们有6种选择,但每个选择都需要有前提条件!
1,把a倒完,需要满足目前a大于0
2,把a填满,需要满足目前a没有满
3, a倒入b中 需要满足 a不为0且b没满!(至于是否倒的完就分类讨论)
另外三种是b,仿造上面a的处理
我们还要记录状态是否重复出现,直接开个二维数组,vis[n][n]来代表每种状态
记录路径我们就可以用一个vector数组或者string类来加上他的父亲和自己新增的!!就好了
还是上代码把
int a,b,c;
struct node
{
int a,b;
vector<int>v;这里我采用的是vector记录路径
};
string ope[6]={"FILL(1)","FILL(2)","DROP(1)","DROP(2)","POUR(1,2)","POUR(2,1)"};
int vis[maxn][maxn];
void bfs()
{
queue<node>que;
node tmp;
tmp.a=0;
tmp.b=0;
que.push(tmp);
ms(vis,0);
vis[0][0]=1;
while(!que.empty())
{
tmp=que.front();
que.pop();
if(tmp.a==c||tmp.b==c)
{
int len=tmp.v.size();
cout<<len<<endl;
rep(i,0,len-1)
{
int pos=tmp.v[i];
cout<<ope[pos]<<endl;
}
return ;
}
node nxt;
//0
if(a-tmp.a>0)
{
注意这里每个情况都需要重新覆盖一次以免前面的会干扰
nxt=tmp;
nxt.a=a;
nxt.v.pb(0);
if(!vis[nxt.a][nxt.b])
{
que.push(nxt);
vis[nxt.a][nxt.b]=1;
}
}
//1
if(b-tmp.b>0)
{
nxt=tmp;
nxt.b=b;
nxt.v.pb(1);
if(!vis[nxt.a][nxt.b])
{
que.push(nxt);
vis[nxt.a][nxt.b]=1;
}
}
//2
if(tmp.a>0)
{
nxt=tmp;
nxt.a=0;
nxt.v.pb(2);
if(!vis[nxt.a][nxt.b])
{
que.push(nxt);
vis[nxt.a][nxt.b]=1;
}
}
//3
if(tmp.b>0)
{
nxt=tmp;
nxt.b=0;
nxt.v.pb(3);
if(!vis[nxt.a][nxt.b])
{
que.push(nxt);
vis[nxt.a][nxt.b]=1;
}
}
//4
if(tmp.a>0&&b-tmp.b>0)
{
nxt=tmp;
if(nxt.a>b-nxt.b)
{
nxt.a-=(b-nxt.b);
nxt.b=b;
}
else
{
nxt.b+=nxt.a;
nxt.a=0;
}
nxt.v.pb(4);
if(!vis[nxt.a][nxt.b])
{
que.push(nxt);
vis[nxt.a][nxt.b]=1;
}
}
//5
if(tmp.b>0&&a-tmp.a>0)
{
nxt=tmp;
if(nxt.b>a-nxt.a)
{
nxt.b-=(a-nxt.a);
nxt.a=a;
}
else
{
nxt.a+=nxt.b;
nxt.b=0;
}
nxt.v.pb(5);
if(!vis[nxt.a][nxt.b])
{
que.push(nxt);
vis[nxt.a][nxt.b]=1;
}
}
}
cout<<"impossible"<<endl;
}
I . FZU 2150 Fire Game
大概意思是给出一个地图,可以在任意两点(可以重叠)放火,火只会在一个连通块之内蔓延(仅四个方向,不算对角线),求问是否可以烧完,若可以输出最短时间
首先连通块大于2的肯定不可以,等于2的找到最短的,为1就需要很复杂了还不好弄,
我们可以不管都多少个连通块,直接暴力枚举任意两个符合条件的点,之后bfs看是否全部烧完,烧完了就更新出最短的时间这样就不易出bug了
struct node
{
int x,y;
int step;
};
void bfs(node a,node b)
{
queue<node>que;
que.push(a);
que.push(b);
ms(vis,0);
vis[a.x][a.y]=1;
vis[b.x][b.y]=1;
while(!que.empty())
{
node tmp=que.front();
num=max(num,tmp.step);
que.pop();
int x=tmp.x;
int y=tmp.y;
rep(i,0,3)
{
int tx=x+nx[i];
int ty=y+ny[i];
if(tx<1||tx>n||ty<1||ty>m||vis[tx][ty]||maze[tx][ty]=='.')
continue;
vis[tx][ty]=1;
node nxt;
nxt.x=tx;
nxt.y=ty;
nxt.step=tmp.step+1;
que.push(nxt);
}
}
}
int solve()
{
vector<node>v;
rep(i,1,n)
{
rep(j,1,m)
{
if(maze[i][j]=='#')
{
node tmp;
tmp.x=i;
tmp.y=j;
tmp.step=0;
v.pb(tmp);
}
}
}
int len=v.size();
int ans=-1;
暴力枚举点
rep(i,0,len-1)
{
rep(j,0,len-1)
{
num=0;
bfs(v[i],v[j]); bfs
bool flag=true;
rep(i,1,n)
{
rep(j,1,m)
{
if(maze[i][j]=='#'&&vis[i][j]==0)
{
flag=false;
break;
}
}
if(!flag)
{
break;
}
}
if(flag)看是否符合条件
{
if(ans==-1)
{
ans=num;
}
else
{
ans=min(ans,num);
}
}
}
}
return ans;
}
J . UVA 11624 Fire
给出你所在的位置,和火的位置(可能不止一堆)每分钟火会蔓延一格,你可以自己走一格,求问是否你能走出去
刚开始的思路是bfs人的路线,每次bfs更新所有的火的蔓延情况,但是一直超时
我们只需要把火和人一起bfs就好了,用一个f变量来表示当前是人还是火就可以了,注意的是火蔓延过的地方已经没有了用处,人走过的地方也没有了用处,因为蔓延过了再蔓延过来毫无意义,人走过的地方蔓延来了火也无济于事,追不上人,所以我们每次bfs都要把当前的地址改为不受影响的墙再向下bfs就可以优化很多时间,需要注意的是我们要先处理火再处理人这样可以省去很多不必要且难算的判断,因为如果先弄的人然后人走到这里,火又过来那当然不可以,所以我们遍历两边,先遍历出来所有的火放进队列,再遍历人放进去,这样我们每次扩展就是考虑了火已经蔓延好了,这样人就不会踏入火中了
struct node
{
int x,y;
int s,f;
};
void bfs()
{
queue<node>que;
rep(i,1,n)
{
rep(j,1,m)
{
if(str[i][j]=='F')
{
node tmp;
tmp.x=i;
tmp.y=j;
tmp.f=0;
que.push(tmp);
}
}
}
rep(i,1,n)
{
rep(j,1,m)
{
if(str[i][j]=='J')
{
str[i][j]='#';
node tmp;
tmp.x=i;
tmp.y=j;
tmp.s=0;
tmp.f=1;
que.push(tmp);
}
}
}
while(!que.empty())
{
node now=que.front();
que.pop();
//cout<<now.x<<" "<<now.y<<" "<<now.f<<" "<<str[now.x][str[now.y]endl;
if(now.f==1)///人在跑
{
if(now.x==1||now.x==n||now.y==1||now.y==m)
{
flag=1;
ans=now.s+1;
return ;
}
vis[now.x][now.y]=1;
rep(i,0,3)
{
int x=now.x+nx[i];
int y=now.y+ny[i];
if(x<1||x>n||y<1||y>m||vis[x][y]||str[x][y]!='.')
continue;
str[x][y]='#';
vis[x][y]=1;
node nxt;
nxt.x=x;
nxt.y=y;
nxt.f=1;
nxt.s=now.s+1;
que.push(nxt);
}
}
else
{
vis[now.x][now.y]=1;
str[now.x][now.y]='#';
rep(i,0,3)
{
int x=now.x+nx[i];
int y=now.y+ny[i];
if(x<1||x>n||y<1||y>m||vis[x][y]||str[x][y]!='.')
continue;
str[x][y]='F';
vis[x][y]=1;
node nxt;
nxt.x=x;
nxt.y=y;
nxt.f=0;
que.push(nxt);
}
}
}
}
void solve()
{
ms(vis,0);
flag=0,ans=inf;
n=read(),m=read();
rep(i,1,n)
{
scanf("%s",str[i]+1);
}
bfs();
if(flag)
{
printf("%d\n",ans);
}
else
{
printf("IMPOSSIBLE\n");
}
}
K . POJ 3984 迷宫问题
有了前面记录路径的方法,这个就十分简单了~就是一个bfs加上记录路径就OK了
struct node
{
int x,y;
vector<pii>v;
};
void solve()
{
rep(i,0,4)
{
rep(j,0,4)
{
maze[i][j]=read();
}
}
ms(vis,0);
queue<node>que;
node now;
now.x=0,now.y=0;
now.v.pb(MP(0,0));
que.push(now);
vis[0][0]=1;
while(!que.empty())
{
now=que.front();
que.pop();
int x=now.x,y=now.y;
if(x==4&&y==4)
{
int len=now.v.size()-1;
rep(i,0,len)
{
int a=now.v[i].fi;
int b=now.v[i].se;
printf("(%d, %d)\n",a,b);
}
return ;
}
rep(i,0,3)
{
int tx=x+nx[i];
int ty=y+ny[i];
if(tx<0||tx>4||ty<0||ty>4||vis[tx][ty]||maze[tx][ty]==1)
continue;
vis[tx][ty]=1;
node nxt=now;
nxt.x=tx;
nxt.y=ty;
nxt.v.pb(MP(tx,ty));
que.push(nxt);
}
}
}
L . HDU 1241 Oil Deposits
就是连通块模板题…这里是可以对角线延伸的…十分基础…
void bfs(int x,int y)
{
queue<pii>que;
pii now;
now.fi=x,now.se=y;
que.push(now);
vis[x][y]=1;
maze[x][y]='*';
while(!que.empty())
{
now=que.front();
que.pop();
rep(i,0,7)
{
int tx=now.fi+nx[i];
int ty=now.se+ny[i];
if(tx<1||tx>n||ty<1||ty>m||vis[tx][ty]||maze[tx][ty]!='@')
continue;
vis[tx][ty]=1;
maze[tx][ty]='*';
pii nxt;
nxt.fi=tx,nxt.se=ty;
que.push(nxt);
}
}
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
if(n==0&&m==0)
break;
ms(vis,0);
rep(i,1,n)
{
scanf("%s",maze[i]+1);
}
int ans=0;
rep(i,1,n)
{
rep(j,1,m)
{
if(maze[i][j]=='@')
{
ans++;
bfs(i,j);
}
}
}
printf("%d\n",ans);
}
#ifdef _LOCALE_DEBUG_PAUSE
system("pause");
#endif //_LOCALE_DEBUGE_PAUSE
return 0;
}
M . HDU 1495 非常可乐
这个和前面那个倒水问题一样的,区别是上一个要输出路径,这一个输出次数。。。。
int vis[maxn][maxn][maxn];
int a,b,c,flag,ans;
struct node
{
int l,m,r;
int s;
};
void bfs()
{
if(b&1)
{
return ;
}
vis[0][b][0]=1;
node now;
queue<node>que;
now.l=0,now.m=b,now.r=0;
now.s=0;
que.push(now);
while(!que.empty())
{
now=que.front();
que.pop();
int cnt=0;
int l=now.l,m=now.m,r=now.r;
if(l==b/2) cnt++;
if(m==b/2) cnt++;
if(r==b/2) cnt++;
if(cnt==2)
{
flag=1;
ans=now.s;
return ;
}
///l--m
if(l&&b-m)
{
node nxt=now;
if(l<=b-m){
nxt.m+=l;
nxt.l=0;
nxt.s=now.s+1;
if(!vis[nxt.l][nxt.m][nxt.r]){
que.push(nxt);
vis[nxt.l][nxt.m][nxt.r]=1;
}
}
else
{
nxt.l-=b-m;
nxt.m=b;
nxt.s=now.s+1;
if(!vis[nxt.l][nxt.m][nxt.r]){
que.push(nxt);
vis[nxt.l][nxt.m][nxt.r]=1;
}
}
}
///l--r
if(l&&c-r)
{
node nxt=now;
if(l<=c-r)
{
nxt.r+=l;
nxt.l=0;
nxt.s=now.s+1;
if(!vis[nxt.l][nxt.m][nxt.r]){
que.push(nxt);
vis[nxt.l][nxt.m][nxt.r]=1;
}
}
else
{
nxt.l-=c-r;
nxt.r=c;
nxt.s=now.s+1;
if(!vis[nxt.l][nxt.m][nxt.r]){
que.push(nxt);
vis[nxt.l][nxt.m][nxt.r]=1;
}
}
}
//m--l
if(m&&a-l)
{
node nxt=now;
if(m<=a-l)
{
nxt.l+=m;
nxt.m=0;
nxt.s=now.s+1;
if(!vis[nxt.l][nxt.m][nxt.r]){
que.push(nxt);
vis[nxt.l][nxt.m][nxt.r]=1;
}
}
else
{
nxt.m-=a-l;
nxt.l=a;
nxt.s=now.s+1;
if(!vis[nxt.l][nxt.m][nxt.r]){
que.push(nxt);
vis[nxt.l][nxt.m][nxt.r]=1;
}
}
}
//m--r
if(m&&c-r)
{
node nxt=now;
if(m<=c-r)
{
nxt.r+=m;
nxt.m=0;
nxt.s=now.s+1;
if(!vis[nxt.l][nxt.m][nxt.r]){
que.push(nxt);
vis[nxt.l][nxt.m][nxt.r]=1;
}
}
else
{
nxt.m-=c-r;
nxt.r=c;
nxt.s=now.s+1;
if(!vis[nxt.l][nxt.m][nxt.r]){
que.push(nxt);
vis[nxt.l][nxt.m][nxt.r]=1;
}
}
}
//r--l
if(r&&a-l)
{
node nxt=now;
if(r<=a-l)
{
nxt.l+=r;
nxt.r=0;
nxt.s=now.s+1;
if(!vis[nxt.l][nxt.m][nxt.r]){
que.push(nxt);
vis[nxt.l][nxt.m][nxt.r]=1;
}
}
else
{
nxt.r-=a-l;
nxt.l=a;
nxt.s=now.s+1;
if(!vis[nxt.l][nxt.m][nxt.r]){
que.push(nxt);
vis[nxt.l][nxt.m][nxt.r]=1;
}
}
}
//r--m
if(r&&b-m)
{
node nxt=now;
if(r<=b-m)
{
nxt.m+=r;
nxt.r=0;
nxt.s=now.s+1;
if(!vis[nxt.l][nxt.m][nxt.r]){
que.push(nxt);
vis[nxt.l][nxt.m][nxt.r]=1;
}
}
else
{
nxt.r-=b-m;
nxt.m=b;
nxt.s=now.s+1;
if(!vis[nxt.l][nxt.m][nxt.r]){
que.push(nxt);
vis[nxt.l][nxt.m][nxt.r]=1;
}
}
}
}
}
int main()
{
while(~scanf("%d %d %d",&b,&a,&c))
{
if(a==0&&b==0&&c==0)
break;
ms(vis,0);
flag=0;
bfs();
if(flag)
{
printf("%d\n",ans);
}
else
{
printf("NO\n");
}
}
#ifdef _LOCALE_DEBUG_PAUSE
system("pause");
#endif //_LOCALE_DEBUGE_PAUSE
return 0;
}
N - HDU 2612 Find a way
题目意思:位于Y和M两点的人要去同一个肯德基店会面(@)
求出最短的两个人一起到的时间,
双向bfs…
开两个数组记录下,两个人到每个肯德基店的最短时间最后找出之和最短的就OK了
我莫名其妙MLE了…瞎改了改就AC了…玄学…
//#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<cmath>
#include<map>
#include<utility>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,n,a) for(int i=n;i>=a;i--)
#define ms(arr,x) memset((arr),x,sizeof(arr))
#define IOS ios::sync_with_stdio(false),cin.tie(NULL)
#define ll long long
#define MP make_pair
#define pb push_back
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define endl '\n'
#define fi first
#define se second
using namespace std;
typedef pair<int,int> pii;
inline int read()
{
int ans=0,sign=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
sign=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
ans=ans*10+(ch-'0');
ch=getchar();
}
return sign*ans;
}
const int mod=1e9+7;
const double PI=acos(-1.0);
const double eps=1e-5;
const int maxn=205;
int vis1[maxn][maxn],vis2[maxn][maxn];
char str[maxn][maxn];
int n,m;
int nx[4]={0,1,0,-1};
int ny[4]={1,0,-1,0};
struct node
{
int x,y,s,f;
};
int bfs()
{
ms(vis1,-1),ms(vis2,-1);
int s1x=-1,s2x=-1,s1y=-1,s2y=-1;
rep(i,1,n)
{
rep(j,1,m)
{
if(str[i][j]=='Y')
{
str[i][j]='.';
s1x=i;
s1y=j;
}
if(str[i][j]=='M')
{
str[i][j]='.';
s2x=i;
s2y=j;
}
}
if(s1x!=-1&&s2x!=-1)
{
break;
}
}
queue<node>que;
node now;
now.x=s1x,now.y=s1y,now.s=0,now.f=1;
que.push(now);
now.x=s2x,now.y=s2y,now.s=0,now.f=2;
que.push(now);
while(!que.empty())
{
now=que.front();
que.pop();
int f=now.f;
if(f==1)
{
int x=now.x,y=now.y,s=now.s;
vis1[x][y]=s;
rep(i,0,3)
{
int tx=x+nx[i];
int ty=y+ny[i];
if(tx<1||tx>n||ty<1||ty>m||vis1[tx][ty]!=-1||str[tx][ty]=='#')
continue;
node nxt;
nxt.x=tx,nxt.y=ty,nxt.s=s+1,nxt.f=1;
vis1[tx][ty]=nxt.s;
que.push(nxt);
}
}
else
{
int x=now.x,y=now.y,s=now.s;
vis2[x][y]=s;
rep(i,0,3)
{
int tx=x+nx[i];
int ty=y+ny[i];
if(tx<1||tx>n||ty<1||ty>m||vis2[tx][ty]!=-1||str[tx][ty]=='#')
continue;
node nxt;
nxt.x=tx,nxt.y=ty,nxt.s=s+1,nxt.f=2;
vis2[tx][ty]=nxt.s;
que.push(nxt);
}
}
}
int dis=inf;
rep(i,1,n)
{
rep(j,1,m)
{
if(str[i][j]=='@'&&vis1[i][j]!=-1&&vis2[i][j]!=-1)
{
dis=min(dis,vis1[i][j]+vis2[i][j]);
}
}
}
return dis*11;
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
rep(i,1,n)
{
scanf("%s",str[i]+1);
}
cout<<bfs()<<endl;
}
#ifdef _LOCALE_DEBUG_PAUSE
system("pause");
#endif //_LOCALE_DEBUGE_PAUSE
return 0;
}
终于完结了第一个专题的总结…害