板子题,上次课也有讲,bfs、dfs均可以(区别:bfs较快,dfs较简单)
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pi acos(-1.0);
using namespace std;
const int maxn=1e5+5;
int n,m;
char mp[25][25];
int vis[25][25],dir[4][2]={-1,0,1,0,0,-1,0,1};
struct node{
int x,y;
node(int xx,int yy){
x=xx,y=yy;
}
};
int check(int x,int y){
if(x>=1&&x<=n&&y>=1&&y<=m&&vis[x][y]==0&&mp[x][y]=='.') return 1;
return 0;
}
void bfs(int x,int y){
int ans=1;
queue<node>q;
q.push(node(x,y));
vis[x][y]=1;
while(!q.empty()){
node now=q.front();
q.pop();
for(int i=0;i<4;i++){
int fx=now.x+dir[i][0];
int fy=now.y+dir[i][1];
if(check(fx,fy)){
vis[fx][fy]=1;
q.push(node(fx,fy));
ans++;
}
}
}
printf("%d\n",ans);
return ;
}
int main(){
while(~scanf("%d%d",&m,&n)){
if(!n&&!m) break;
memset(vis,0,sizeof(vis));
int sx,sy;
for(int i=1;i<=n;i++){
scanf("%s",mp[i]+1);
for(int j=1;j<=m;j++){
if(mp[i][j]=='@'){
sx=i,sy=j;
}
}
}
bfs(sx,sy);
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pi acos(-1.0);
using namespace std;
const int maxn=1e5+5;
int n,m;
char mp[25][25];
int vis[25][25],dir[4][2]={-1,0,1,0,0,-1,0,1};
int check(int x,int y){
if(x>=1&&x<=n&&y>=1&&y<=m&&vis[x][y]==0&&mp[x][y]=='.') return 1;
return 0;
}
int ans;
void dfs(int x,int y){
for(int i=0;i<4;i++){
int fx=x+dir[i][0];
int fy=y+dir[i][1];
if(check(fx,fy)){
vis[fx][fy]=1;
ans++;
dfs(fx,fy);
}
}
}
int main(){
while(~scanf("%d%d",&m,&n)){
if(!n&&!m) break;
memset(vis,0,sizeof(vis));
int sx,sy;
for(int i=1;i<=n;i++){
scanf("%s",mp[i]+1);
for(int j=1;j<=m;j++){
if(mp[i][j]=='@'){
sx=i,sy=j;
}
}
}
ans=1,vis[sx][sy]=1;
dfs(sx,sy);
printf("%d\n",ans);
}
return 0;
}
bfs板子题,可能稍微要处理的就是保存路径。简单看了下大家的代码,很多都是保存前驱结点,然后递归打印的。这里介绍一种更加简单的方法,直接可以保存在一个字符串中,具体见代码。
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pi acos(-1.0);
using namespace std;
const int maxn=1e5+5;
int n,m;
int mp[10][10];
int vis[10][10],dir[4][2]={-1,0,1,0,0,-1,0,1};
struct node{
int x,y;
string s;
node(int xx,int yy,string ss){
x=xx,y=yy,s=ss;
}
};
int check(int x,int y){
if(x>=0&&x<5&&y>=0&&y<5&&vis[x][y]==0&&mp[x][y]==0) return 1;
return 0;
}
void bfs(int sx,int sy){
vis[sx][sy]=1;
queue<node>q;
q.push(node(sx,sy,"00"));
while(!q.empty()){
node now=q.front();
q.pop();
if(now.x==4&&now.y==4){
for(int i=0;i<now.s.size();i+=2){
cout<<'('<<now.s[i]<<", "<<now.s[i+1]<<')'<<'\n';
}
break;
}
for(int i=0;i<4;i++){
int fx=now.x+dir[i][0];
int fy=now.y+dir[i][1];
if(check(fx,fy)){
vis[fx][fy]=1;
string str=now.s;
str+=fx+'0';str+=fy+'0';
q.push(node(fx,fy,str));
}
}
}
return ;
}
int main(){
for(int i=0;i<5;i++){
for(int j=0;j<5;j++){
scanf("%d",&mp[i][j]);
}
}
bfs(0,0);
}
八连通块板子题。dfs处理会稍微简单点。
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pi acos(-1.0);
using namespace std;
const int maxn=1e5+5;
int n,m;
char mp[110][110];
int dirx[]={1,1,1,-1,-1,-1,0,0};
int diry[]={1,-1,0,-1,0,1,-1,1};
int check(int x,int y){
if(x>=1&&x<=n&&y>=1&&y<=m&&mp[x][y]=='@') return 1;
return 0;
}
void dfs(int x,int y){
for(int i=0;i<8;i++){
int fx=x+dirx[i];
int fy=y+diry[i];
if(check(fx,fy)){
mp[fx][fy]='*';
dfs(fx,fy);
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
if(!n&&!m) break;
for(int i=1;i<=n;i++){
scanf("%s",mp[i]+1);
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]=='@'){
ans++;
mp[i][j]='*';
dfs(i,j);
}
}
}
printf("%d\n",ans);
}
return 0;
}
同样是八连通块板子题。
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pi acos(-1.0);
using namespace std;
const int maxn=1e5+5;
int n,m;
char mp[110][110];
int dirx[]={1,1,1,-1,-1,-1,0,0};
int diry[]={1,-1,0,-1,0,1,-1,1};
int check(int x,int y){
if(x>=1&&x<=n&&y>=1&&y<=m&&mp[x][y]=='W') return 1;
return 0;
}
void dfs(int x,int y){
for(int i=0;i<8;i++){
int fx=x+dirx[i];
int fy=y+diry[i];
if(check(fx,fy)){
mp[fx][fy]='.';
dfs(fx,fy);
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++){
scanf("%s",mp[i]+1);
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]=='W'){
ans++;
mp[i][j]='.';
dfs(i,j);
}
}
}
printf("%d\n",ans);
}
return 0;
}
经典N皇后问题,由于n比较小,可以考虑回溯加剪枝即可。
但是暴力的回溯加剪枝会超时,可以考虑先打表,将n=1到10的结果保存到数组中,最后O(1)查询即可。
但是可以思考下,如果n比较大的话该用什么方法求解呢?可以看看网上大牛的博客学习学习。
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pi acos(-1.0);
using namespace std;
const int maxn=1e5+5;
int l[20],r[20],col[20];
int f[15],num;
void dfs(int i,int n){
if(i==n+1){
num++;
return ;
}
for(int j=1;j<=n;j++){
if(l[i+j]==0&&r[i-j+n]==0&&col[j]==0){
col[j]=1,l[i+j]=1,r[i-j+n]=1;
dfs(i+1,n);
col[j]=0,l[i+j]=0,r[i-j+n]=0;
}
}
return ;
}
int main(){
memset(f,0,sizeof(f));
for(int i=1;i<=10;i++){
num=0;
memset(col,0,sizeof(col));
memset(r,0,sizeof(r));
memset(l,0,sizeof(l));
dfs(1,i);
f[i]=num;
}
int n;
while(~scanf("%d",&n)&&n){
printf("%d\n",f[n]);
}
return 0;
}
简单DFS问题,直接暴力搜即可。
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pi acos(-1.0);
using namespace std;
const int maxn=1e5+5;
string s[maxn];
int vis[maxn];
int n,flag;
void dfs(string s1) {
if(flag) return ;
if(s1[s1.size()-1]=='m') {
flag=1;
return ;
}
for(int i=1; i<=n; i++) {
if(vis[i]==0&&s[i][0]==s1[s1.size()-1]) {
vis[i]=1;
dfs(s[i]);
vis[i]=0;
}
}
}
int main() {
while(cin>>s[1]) {
n=1;
while(cin>>s[++n]) {
if(s[n]=="0") {
n--;
break;
}
}
for(int i=1; i<=n; i++) {
if(s[i][0]=='b') {
flag=0;
vis[i]=1;
dfs(s[i]);
vis[i]=0;
if(flag) break;
}
}
if(flag) printf("Yes.\n");
else printf("No.\n");
}
}
无向图最长路径,由于结点比较少,可以直接考虑对每个结点做dfs,在所有的路径中选择最长的即可。
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pi acos(-1.0);
using namespace std;
const int maxn=1e5+5;
int n,m,ans;
int mp[110][110],vis[110][110];
void dfs(int u,int cnt){
ans=max(ans,cnt);
for(int i=0;i<n;i++){
if(mp[u][i]&&vis[u][i]==0){
vis[u][i]=vis[i][u]=1;
dfs(i,cnt+1);
vis[u][i]=vis[i][u]=0;
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
if(n==0&&m==0) break;
memset(mp,0,sizeof(mp));
int u,v;
for(int i=1;i<=m;i++){
scanf("%d%d",&u,&v);
mp[u][v]=mp[v][u]=1;
}
ans=0;
for(int i=0;i<n;i++){
memset(vis,0,sizeof(vis));
dfs(i,0);
}
printf("%d\n",ans);
}
return 0;
}
类似于n皇后,可以直接按照一行一行的放棋子,如果当前行能放,则直接跳转至下一行,且对放置过了的棋子计数加一;如果不能放,则直接跳转至下一行,放置过的棋子数量不变。
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pi acos(-1.0);
using namespace std;
const int maxn=1e5+5;
int n,k,ans;
char mp[15][15];
int col[15];
void dfs(int x,int cnt){
if(cnt==k){
ans++;return ;
}
if(x==n+1) return ;
for(int j=1;j<=n;j++){
if(mp[x][j]=='#'&&col[j]==0){
col[j]=1;
dfs(x+1,cnt+1);
col[j]=0;
}
}
dfs(x+1,cnt);
}
int main(){
while(~scanf("%d%d",&n,&k)){
if(n==-1&&k==-1) break;
for(int i=1;i<=n;i++){
scanf("%s",mp[i]+1);
}
memset(col,0,sizeof(col));
ans=0;
dfs(1,0);
printf("%d\n",ans);
}
return 0;
}
从题干中发现求最少的步数,当然优先考虑BFS,于是直接按照题意搜索即可。
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pi acos(-1.0);
using namespace std;
const int maxn=1e5;
int n,k;
int vis[maxn+5];
struct node{
int x,step;
node(int xx,int d){
x=xx,step=d;
}
};
void bfs(int x){
int ans=0;
queue<node>q;
q.push(node(x,0));
vis[x]=1;
while(!q.empty()){
node now=q.front();q.pop();
if(now.x==k){
ans=now.step;break;
}
if(now.x-1>=0&&vis[now.x-1]==0){
vis[now.x-1]=1;q.push(node(now.x-1,now.step+1));
}
if(now.x+1<=maxn&&vis[now.x+1]==0){
vis[now.x+1]=1;q.push(node(now.x+1,now.step+1));
}
if(2*now.x<=maxn&&vis[now.x+now.x]==0){
vis[now.x+now.x]=1;q.push(node(2*now.x,now.step+1));
}
}
printf("%d\n",ans);
}
int main(){
while(~scanf("%d%d",&n,&k)){
memset(vis,0,sizeof(vis));
bfs(n);
}
return 0;
}
同样是比较简单的搜索问题,由于求最短步数,同样优先考虑bfs,于是直接对起点做bfs即可。需要注意方向数组。
#include
#include
#include
#include
#include
#include
#include
#include
#define ll long long
#define pi acos(-1.0);
using namespace std;
const int maxn=1e5;
int vis[10][10],sx,sy,ex,ey;
string s1,s2;
int dirx[]={2,2,-2,-2,1,1,-1,-1};
int diry[]={1,-1,1,-1,2,-2,2,-2};
struct node{
int x,y,step;
node(int xx,int yy,int d){
x=xx,y=yy,step=d;
}
};
void bfs(int sx,int sy){
int ans=0;
queue<node>q;
q.push(node(sx,sy,0));
vis[sx][sy]=1;
while(!q.empty()){
node now=q.front();q.pop();
if(now.x==ex&&now.y==ey){
ans=now.step;break;
}
for(int i=0;i<8;i++){
int fx=now.x+dirx[i];
int fy=now.y+diry[i];
if(vis[fx][fy]==0&&fx>=1&&fx<=8&&fy>=1&&fy<=8){
vis[fx][fy]=1;
q.push(node(fx,fy,now.step+1));
//cout<
}
}
}
cout<<"To get from "<<s1<<" to "<<s2<<" takes "<<ans<<" knight moves.\n";
return ;
}
int main(){
while(cin>>s1>>s2){
sx=s1[0]-'a'+1,sy=s1[1]-'0';
ex=s2[0]-'a'+1,ey=s2[1]-'0';
//cout<
memset(vis,0,sizeof(vis));
bfs(sx,sy);
}
return 0;
}
由于是需要求两个起点的最短路问题,可以直接对两个起点分别跑一次bfs,然后遍历整张地图,对每个’@'进行判断,选择最最短步数。
#include
#include
#include
#include
#include
#include
#include
#include
#define inf 0x3f3f3f3f
#define ll long long
#define pi acos(-1.0);
using namespace std;
const int maxn=1e5;
char mp[210][210];
int vis[210][210],dis1[210][210],dis2[210][210];
int dir[4][2]={-1,0,1,0,0,-1,0,1};
int n,m;
struct node{
int x,y,step;
node(int xx,int yy,int d){
x=xx,y=yy,step=d;
}
};
int check(int x,int y){
if(x>=1&&x<=n&&y>=1&&y<=m&&!vis[x][y]&&mp[x][y]!='#') return 1;
return 0;
}
void bfs(int x,int y,int flag){
queue<node>q;
q.push(node(x,y,0));
vis[x][y]=1;
while(!q.empty()){
node now=q.front();q.pop();
if(mp[now.x][now.y]=='@'){
if(flag==0) dis1[now.x][now.y]=now.step;
else dis2[now.x][now.y]=now.step;
}
for(int i=0;i<4;i++){
int fx=now.x+dir[i][0];
int fy=now.y+dir[i][1];
if(check(fx,fy)){
vis[fx][fy]=1;
q.push(node(fx,fy,now.step+1));
}
}
}
}
int main(){
while(~scanf("%d%d",&n,&m)){
int sx1,sy1,sx2,sy2;
for(int i=1;i<=n;i++){
scanf("%s",mp[i]+1);
for(int j=1;j<=m;j++){
if(mp[i][j]=='Y'){
sx1=i,sy1=j;
}
if(mp[i][j]=='M'){
sx2=i,sy2=j;
}
}
}
memset(dis1,0,sizeof(dis1));
memset(dis2,0,sizeof(dis2));
memset(vis,0,sizeof(vis));
bfs(sx1,sy1,0);
memset(vis,0,sizeof(vis));
bfs(sx2,sy2,1);
int ans=inf;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(mp[i][j]=='@'&&dis1[i][j]&&dis2[i][j]&&dis1[i][j]+dis2[i][j]<ans){
ans=dis1[i][j]+dis2[i][j];
}
}
}
printf("%d\n",ans*11);
}
return 0;
}
数据比较弱,用long long保存或者 _int64都可以过,知道这个之后,题目就变得很水了,直接dfs暴力搜即可。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) x&(-x)
#define ll long long
#define inf 0x3f3f3f3f
#define mod 1000
using namespace std;
const double pi=acos(-1.0);
const int maxn=1e6;
const double eps=1e-8;
int n;
int flag;
void dfs(int step,ll num){
if(step>19||flag==1)
return ;
if(num%n==0){
flag=1;
printf("%lld\n",num);
return ;
}
dfs(step+1,num*10);
dfs(step+1,num*10+1);
return ;
}
int main(){
while(~scanf("%d",&n)){
if(n==0)
break;
flag=0;
dfs(1,1);
}
return 0;
}
经典三维迷宫问题求最短路问题,只需考虑方向数组由2维变3维即可,直接对起点跑一遍bfs即可。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) x&(-x)
#define ll long long
#define inf 0x3f3f3f3f
#define mod 1000
using namespace std;
const double pi=acos(-1.0);
const int maxn=1e6;
const double eps=1e-8;
char mp[35][35][35];
int vis[35][35][35];
int row,col,height;
int sx,sy,sz,ex,ey,ez;
int dirx[6]={0,0,0,0,1,-1};
int diry[6]={0,0,-1,1,0,0};
int dirz[6]={1,-1,0,0,0,0};
int flag; //判断有没有解
struct node{
int x,y,z;
int dis;
node(int xx,int yy,int zz,int diss){
x=xx;
y=yy;
z=zz;
dis=diss;
}
};
int check(int x,int y,int z){
if(x<0||y<0||z<0||x>=height||y>=row||z>=col){
return 0;
}
if(vis[x][y][z]||mp[x][y][z]=='#'){
return 0;
}
return 1;
}
void bfs(){
queue<node>q;
q.push(node(sx,sy,sz,0));
while(!q.empty()){
node now=q.front();
if(now.x==ex&&now.y==ey&&now.z==ez){
printf("Escaped in %d minute(s).\n",now.dis);
flag=1;
return ;
}
q.pop();
for(int i=0;i<6;i++){
int fx=now.x+dirx[i];
int fy=now.y+diry[i];
int fz=now.z+dirz[i];
if(check(fx,fy,fz)){
vis[fx][fy][fz]=1;
q.push(node(fx,fy,fz,now.dis+1));
}
}
}
return ;
}
int main(){
while(~scanf("%d%d%d",&height,&row,&col)){
if(height==0&&row==0&&col==0){
break;
}
memset(vis,0,sizeof(vis));
memset(mp,0,sizeof(mp));
for(int i=0;i<height;i++){
for(int j=0;j<row;j++){
scanf("%s",mp[i][j]);
}
getchar();
}
flag=0;
int flag1=0,flag2=0;
for(int i=0;i<height;i++){
for(int j=0;j<row;j++){
for(int k=0;k<col;k++){
if(mp[i][j][k]=='S'){
sx=i;
sy=j;
sz=k;
flag1=1;
}
if(mp[i][j][k]=='E'){
ex=i;
ey=j;
ez=k;
flag2=1;
}
if(flag1&&flag2){
break;
}
}
if(flag1&&flag2)
break;
}
if(flag1&&flag2){
break;
}
}
bfs();
if(flag==0){
printf("Trapped!\n");
}
}
return 0;
}
BFS+优先队列
需要注意:有多个’r’(即:有多个起点)
常规解法:对每个起点跑一次bfs,然后从中找出最少步数
优秀解法:直接对终点跑一次bfs,由于是优先队列,所以遇到’r’,即可结束。
下面是欧阳亨杰的代码:
#include
using namespace std;
int n,m,vis[205][205],dx,dy,flag;
char mp[205][205];
int d[4][2]={1,0,-1,0,0,1,0,-1};
struct node
{
int x,y,step;
bool operator < (const node &a)const
{
return a.step<step;
}
};
void bfs()
{
memset(vis,0,sizeof(vis));
node a;
a.x=dx;
a.y=dy;
a.step=0;
priority_queue<struct node>p;
p.push(a);
while(!p.empty())
{
a=p.top();
p.pop();
if(mp[a.x][a.y]=='r')
{
flag=1;
printf("%d\n",a.step);
return ;
}
for(int i=0;i<4;i++)
{
node next;
next.x=a.x+d[i][0];
next.y=a.y+d[i][1];
next.step=a.step;
if(next.x>=0&&next.x<n&&next.y>=0&&next.y<m&&mp[next.x][next.y]!='#'&&!vis[next.x][next.y])
{
vis[next.x][next.y]=1;
if(mp[next.x][next.y]=='x')
next.step+=2;
else
next.step+=1;
p.push(next);
}
}
}
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
flag=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
cin>>mp[i][j];
if(mp[i][j]=='a')
{
dx=i;
dy=j;
}
}
bfs();
if(!flag)
printf("Poor ANGEL has to stay in the prison all his life.\n");
}
return 0;
}
直接dfs暴搜即可,看似比较复杂,实则很简单。
#include
#include
#include
#include
using namespace std;
int mp[30][30]; //邻接矩阵
int path[30]; //存放前驱结点
int vis[30]; //标记数组
int m,t; //m表示出发结点,t表示路径的条数
void DFS(int k,int sum)
{
int i;
if(sum==20&&mp[m][k]==1)
{
printf("%d: ",t);
for(int i=1;i<=20;i++)
printf(" %d",path[i]);
printf(" %d\n",m);
t++;
return ;
}
for(int i=1;i<=20;i++)
{
if(vis[i]==0&&mp[k][i]==1)
{
vis[i]=1;
path[sum+1]=i;
DFS(i,sum+1);
vis[i]=0;
}
}
return ;
}
int main()
{
int i;
memset(mp,0,sizeof(mp));
int a,b,c;
for(int i=1;i<=20;i++)
{
scanf("%d%d%d",&a,&b,&c);
mp[i][a]=mp[i][b]=mp[i][c]=1;
}
while(~scanf("%d",&m))
{
if(m==0)
break;
vis[m]=1;
path[1]=m;
t=1;
DFS(m,1);
}
return 0;
}
题意不难,给定a,b;需要按照题目规定的每次改变一位,且保证改变后的数字是素数,问最少需要多少步能从a变成b。
常规解法:直接对个位、十位、百位、千位进行搜索。
简化代码方式:直接用字符串存数字,然后对字符串进行简单处理。下面给出常规解法。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) x&(-x)
#define ll long long
#define inf 0x3f3f3f3f
#define mod 1000
using namespace std;
const double pi=acos(-1.0);
const int maxn=1e5;
const double eps=1e-8;
int t;
int n,m;
int flag;
bool vis[10010];
int check[maxn+10];
void init(){
memset(vis,true,sizeof(vis));
vis[1]=false;
for(int i=2;i<=maxn;i++){
for(int j=i*2;j<=maxn;j+=i){
vis[j]=false;
}
}
return ;
}
struct node{
int x;
int step;
node(int xx,int s){
x=xx;
step=s;
}
};
void bfs(int num,int step){
check[num]=1;
queue<node>q;
q.push(node(num,step));
while(!q.empty()){
node now=q.front();
q.pop();
if(now.x==m){
printf("%d\n",now.step);
flag=1;
return ;
}
for(int i=0;i<=9;i++){ //个位
int fx=(now.x/10)*10+i;
if(check[fx]==0&&vis[fx]==true){
q.push(node(fx,now.step+1));
check[fx]=1;
}
}
for(int i=0;i<=9;i++){ //十位
int fx=(now.x/100)*100+i*10+now.x%10;
if(check[fx]==0&&vis[fx]==true){
q.push(node(fx,now.step+1));
check[fx]=1;
}
}
for(int i=0;i<=9;i++){ //百位
int fx=(now.x/1000)*1000+i*100+now.x%100;
if(check[fx]==0&&vis[fx]==true){
q.push(node(fx,now.step+1));
check[fx]=1;
}
}
for(int i=1;i<=9;i++){ //千位
int fx=i*1000+now.x%1000;
if(check[fx]==0&&vis[fx]==true){
q.push(node(fx,now.step+1));
check[fx]=1;
}
}
}
return ;
}
int main(){
init();
scanf("%d",&t);
while(t--){
flag=0;
memset(check,0,sizeof(check));
scanf("%d%d",&n,&m);
bfs(n,0);
if(flag==0){
printf("Impossible\n");
}
}
return 0;
}
DFS+奇偶剪枝
奇偶剪枝博客
了解了奇偶剪枝后,这题就很水了,下面是廖世兴的代码。
#include
#include
#include
using namespace std;
char graph[10][10];
int sx,sy,dx,dy,n,m,k;
bool flag;
bool visit[10][10];
int turn[4][2]={1,0,-1,0,0,1,0,-1};
void dfs(int x,int y,int count)
{
if(flag)return;
if(x==dx&&y==dy&&count==k){
flag=1;return;
}
if(count>=k)return;
if(graph[x][y]!='X'){
for(int i=0;i<4;i++){
int mx = x+turn[i][0];
int my = y+turn[i][1];
if(graph[mx][my]!='X'&&mx>=1&&mx<=n&&my>=1&&my<=m&&!visit[mx][my]){
visit[mx][my] = 1;
dfs(mx,my,count+1);
visit[mx][my] = 0;
}
}
}
}
int main()
{
while(cin>>n>>m>>k&&n&&m&&k){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
cin>>graph[i][j];
if(graph[i][j]=='S')sx = i,sy = j;
if(graph[i][j]=='D')dx = i,dy = j;
}
}
if(abs(sx-dx)+abs(sy-dy)>k||(sx+sy+dx+dy+k)%2==1){ //奇偶剪枝
cout<<"NO"<<endl;
continue;
}
memset(visit,0,sizeof(visit));
flag=0,visit[sx][sy] = 1;
dfs(sx,sy,0);
if(flag)cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
return 0;
}
搜索+思维。具体见代码。
#include
#include
#include
#include
using namespace std;
/**其中s表示出发站点,e表示末站点,p表示乘客数量*/
struct Order
{
int s,e,p;
}order[30];
int down[10]; //存放在某一站下车的乘客数量
int capacity,stopNum,t; //分别表示车的最大乘客量,站点个数,order数量
int maxValue; //表示最终可以获得的最大利益
int cmp(Order x,Order y)
{
if(x.s!=y.s)
return x.s<y.s;
else
return x.e<y.e;
}
void dfs(int i,int passengerNum,int value) //分别表示已经测试数据的个数,此次乘客数,当前已经获得的利益
{
/**递归结束条件*/
if(i==t)
{
maxValue=max(maxValue,value);
return ;
}
/**把站点为0排除了*/
if(i>0)
{
for(int j=order[i-1].s+1;j<=order[i].s;j++)
passengerNum-=down[j];
}
if(passengerNum+order[i].p<=capacity)
{
down[order[i].e]+=order[i].p;
dfs(i+1,passengerNum+order[i].p,value+order[i].p*(order[i].e-order[i].s));
down[order[i].e]-=order[i].p;
}
dfs(i+1,passengerNum,value);
}
int main()
{
while(~scanf("%d%d%d",&capacity,&stopNum,&t))
{
if(capacity==0&&stopNum==0&&t==0)
break;
for(int i=0;i<t;i++)
scanf("%d%d%d",&order[i].s,&order[i].e,&order[i].p);
/**排序*/
sort(order,order+t,cmp);
maxValue=0;
dfs(0,0,0);
printf("%d\n",maxValue);
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) x&(-x)
#define ll long long
#define inf 0x3f3f3f3f
#define mod 1000
using namespace std;
const double pi=acos(-1.0);
const int maxn=1e6;
const double eps=1e-8;
int temp[20][20];
int mm[20][20];
int mp[20][20];
int n,m;
int dir[5][2]={0,0,1,0,0,1,-1,0,0,-1};
int get(int x,int y){
int c=mp[x][y];
for(int i=0;i<5;i++){
int fx=x+dir[i][0];
int fy=y+dir[i][1];
c+=temp[fx][fy];
}
return c%2;
}
int cal(){
for(int i=2;i<=n;i++){
for(int j=1;j<=m;j++){
if(get(i-1,j)==1)
temp[i][j]=1;
}
}
for(int i=1;i<=m;i++){
if(get(n,i))
return -1;
}
int res=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
res+=temp[i][j];
}
}
return res;
}
int main(){
int minn=-1;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
scanf("%d",&mp[i][j]);
}
}
for(int i=0;i<(1<<n);i++){
memset(temp,0,sizeof(temp));
for(int j=1;j<=n;j++){
temp[1][j]=(i>>(j-1))&1;
}
int num=cal();
if(num>=0&&(minn<0||minn>num)){
minn=num;
memcpy(mm,temp,sizeof(temp));
}
}
if(minn==-1)
printf("IMPOSSIBLE\n");
else{
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(j==m){
printf("%d\n",mm[i][j]);
}
else{
printf("%d ",mm[i][j]);
}
}
}
}
return 0;
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) x&(-x)
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e5+10;
int n,c;
string str,s1,s2;
int solve(){
map<string,int>vis;
string t=s1+s2;
int step=0;
while(t!=str&&vis[t]==0){
vis[t]=1;
step++;
string newString=t;
int index=0;
for(int i=0;i<c;i++){
newString[index++]=t[i+c];
newString[index++]=t[i];
}
t=newString;
}
if(t==str){
return step;
}
return -1;
}
int main(){
scanf("%d",&n);
for(int k=1;k<=n;k++){
cin>>c;
cin>>s1>>s2>>str;
cout<<k<<" "<<solve()<<endl;
}
return 0;
}
思路很简单,直接BFS即可,可能存储路径时会有点麻烦,但是能很好的训练编码能力。
小技巧:一般存储路径建议用字符串存,这样比存前驱要更加方便。
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define lowbit(x) x&(-x)
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e5+10;
int a,b,c;
int vis[110][110];
struct node{
int v1,v2,step;
string str;
node(int vv1,int vv2,string ss,int s){
v1=vv1;
v2=vv2;
step=s;
str=ss;
}
};
int check(int x,int y){
if(vis[x][y]==0&&x>=0&&x<=a&&y>=0&&y<=b)
return 1;
else{
return 0;
}
}
int flag=0;
void bfs(){
queue<node>q;
q.push(node(0,0,"",0));
while(!q.empty()){
node now=q.front();
q.pop();
if(now.v1==c||now.v2==c){
cout<<now.step<<endl;
cout<<now.str;
flag=1;
return ;
}
int x,y;
//FILL操作
x=a;
y=now.v2;
if(check(x,y)){
vis[x][y]=1;
q.push(node(x,y,now.str+"FILL(1)\n",now.step+1));
}
x=now.v1;
y=b;
if(check(x,y)){
vis[x][y]=1;
q.push(node(x,y,now.str+"FILL(2)\n",now.step+1));
}
//DROP操作
x=0;
y=now.v2;
if(check(x,y)){
vis[x][y]=1;
q.push(node(x,y,now.str+"DROP(1)\n",now.step+1));
}
x=now.v1;
y=0;
if(check(x,y)){
vis[x][y]=1;
q.push(node(x,y,now.str+"DROP(2)\n",now.step+1));
}
//POUR操作
int num=b-now.v2;
if(now.v1>=num){
x=now.v1-num;
y=b;
}
else{
x=0;
y=now.v2+now.v1;
}
if(check(x,y)){
vis[x][y]=1;
q.push(node(x,y,now.str+"POUR(1,2)\n",now.step+1));
}
num=a-now.v1;
if(now.v2>=num){
x=a;
y=now.v2-num;
}
else{
x=now.v1+now.v2;
y=0;
}
if(check(x,y)){
vis[x][y]=1;
q.push(node(x,y,now.str+"POUR(2,1)\n",now.step+1));
}
}
return ;
}
int main(){
while(~scanf("%d%d%d",&a,&b,&c)){
flag=0;
bfs();
if(flag==0){
printf("impossible\n");
}
}
return 0;
}