[Noip2017普及组]棋盘

写起来有点烦...

#include<bits/stdc++.h>
using namespace std;
const int N=105;
const int inf=0x3f3f3f3f;
int dir[4][2]={{-1,0},{0,-1},{0,1},{1,0}};//四个方向定义
int s[N][N],p[N][N],n,m,flag=0,ans=inf;
void dfs(int x,int y,int cnt,int k)
{
	if(cnt>=p[x][y]) return; //如果花费已经大于最小值,则停止搜索
	p[x][y]=cnt; //否则更新该点最小值
	if(x==n&&y==n)//判断是否到达终点
	{ 
		flag=1; //标记为可以到达终点,为主函数判断作铺垫
		ans=min(ans,cnt);//更新答案
		return;
	}
	for(int i=0;i<4;i++)//枚举四个方向
	{
		int tx=x+dir[i][0];//求出往当前方向走的坐标
		int ty=y+dir[i][1];
		if(tx<1||tx>n||ty<1||ty>n) continue;//判断是否越界
		if(s[tx][ty]!=0)//该点有颜色
		{ 
			if(s[x][y]==s[tx][ty])
			   dfs(tx,ty,cnt,0); //如果该点的颜色与上一个经过的点颜色一样则不需要花费魔法
			else 
			    dfs(tx,ty,cnt+1,0);//若颜色不一样,则花费+1
		}
		else
		{
			if(k==0)//若上一次没有使用魔法
			{ 
				s[tx][ty]=s[x][y]; //改变颜色
				dfs(tx,ty,cnt+2,1); //花费+2,标记使用了魔法
				s[tx][ty]=0; //回溯
			}
		}
	}
}
int main()
{
   	scanf("%d%d",&n,&m);
   	for(int i=1;i<=n;i++)
   		for(int j=1;j<=n;j++)p[i][j]=inf; //先赋值为一个极大值
   	for(int i=0;i<m;i++)
	{
   		int x,y,c;
   		scanf("%d%d%d",&x,&y,&c);
   		if(c==0)s[x][y]=2; //格子为红色
		else s[x][y]=c;//格子为黄色
   	}
   	dfs(1,1,0,0);//深搜
   	if(flag) printf("%d
",ans);
   	else printf("-1
");
    return 0;
}

  

#include<bits/stdc++.h>
using namespace std;
#define inf 0x4f4f4f4f
int f[1001][1001];
int mp[1001][1001];
int ans=inf;
int dx[4]= {-1,0,1,0};
int dy[4]= {0,-1,0,1};
int m,n;
inline void DFS(int x,int y,int tot,bool flag) 
{
    if(x < 1 || y < 1 || x > n || y > n) 
	    return;
    if(!f[x][y]) //如果当前点是无色的,则无效的 
	   return;
   if(tot>= mp[x][y]) //如果用的费用大于当前点的 
	    return;
    mp[x][y] = tot;
    if(x == n && y == n) 
	{
        if(tot < ans) 
		   ans = tot;
        return;
    }
    for(register int i=0; i<=3; ++i) 
	{
        int xx=x+dx[i];
        int yy=y+dy[i];
        if(f[xx][yy]) //如果是有color的 
		{
            if(f[xx][yy]==f[x][y]) //如果相同的color的 
                DFS(xx,yy,tot,false);
            else
                DFS(xx,yy,tot+1,false);
        } 
		else 
		if(!f[xx][yy]&&!flag) 
		//如果走到的格子是无color的,且可以使用改色技能 
		{
            f[xx][yy]=f[x][y];
            DFS(xx,yy,tot+2,true);
            f[xx][yy]=0;
        }
 
    }
}
int main() 
{
    scanf("%d%d",&n,&m);
    memset(mp,inf,sizeof(mp));
    for(register int i=1; i<=m; i++) 
	{
        int x,y,z;
        scanf("%d%d%d",&x,&y,&z);
        f[x][y]=z+1;
    }
    DFS(1,1,0,false);
    if(ans==inf)printf("-1
");
    else printf("%d
",ans);
    return 0;
}

  

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int m,n;
int mp[110][110],f[110][110];
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
void dfs(int x,int y,int z)
{
for(int i=0;i<4;i++)
{
int tx=x+dx[i];
int ty=y+dy[i];
if(tx<1||ty<1||tx>m||ty>m)
continue;
int r=-1;
if(mp[x][y]==mp[tx][ty]&&mp[tx][ty])
//如果是有color的,且同色的
r=0;
else
{
if(mp[tx][ty])
//如果目标点是有色的
r=1;
if(!mp[tx][ty]&&z)
//如果目标点是无色的,且可以采用改色的技能时
r=2;
}
if(r!=-1&&(f[x][y]+r<f[tx][ty]||!f[tx][ty]))
//如果可以移动的话,且移到目标的代价更优,或者目标点从前没走过
{
f[tx][ty]=f[x][y]+r;
if(r==2)
//如果使用了改色的技能的话
{
mp[tx][ty]=mp[x][y];
dfs(tx,ty,0);
//走到(tx,ty)且改色技能失效
mp[tx][ty]=0;
}
else
dfs(tx,ty,1);
}
}
}
int main()
{
f[1][1]=1;
scanf("%d%d",&m,&n);
int x,y,c;
for(int i=1;i<=n;i++)
{
scanf("%d%d%d",&x,&y,&c);
mp[x][y]=c+1;
//题面居然会0代表红色,于是给所有color加1
}
dfs(1,1,1);
printf("%d",f[m][m]-1);
return 0;
}

  

原文地址:https://www.cnblogs.com/cutemush/p/13673279.html