搜索?——P3956 [NOIP2017 普及组] 棋盘

这篇具有很好参考价值的文章主要介绍了搜索?——P3956 [NOIP2017 普及组] 棋盘。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

传送门: [NOIP2017 普及组] 棋盘 - 洛谷

思路: 将棋盘的每一个格子看做一个点,建一个无向图用来跑最短路.

这道题本应用搜索来做,但是转换成最短路好像简单点

建图:

1.对于已经有颜色的格子,在扫描四个方向的格子对相同颜色的建条长度为0的边,不同颜色的建条长度为1的边

2.对于没有颜色的格子,对于四个方向所有有颜色的格子都要先建条长度为2的边,再在四周有颜色格子之间两两建边,颜色相同就建长度为2的边,颜色不同就建长度为3的边,如下图所示一个没有颜色的格子四周格子的边

搜索?——P3956 [NOIP2017 普及组] 棋盘

建好边就可以跑spfa了,但是这个做法只有90分

90分(满分100)的代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int,int> PII;
const double PI=3.1415926535;
const int N=1e6+10;
bool st[N];
int d[110][110];
int dx[4]={-1,0,1,0};
int dy[4]={0,1,0,-1
};
int e[N],ne[N],w[N],h[N],idx;
int dist[N];
int n,m;
void add(int a,int b,int c)
{
    e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++;
}
void spfa()
{
    memset(dist,0x3f,sizeof dist);
    dist[m+1]=0;
    queue<int>que;
    que.push(m+1);
    while(que.size())
    {
        int t=que.front();
        que.pop();
        st[t]=false;
        for(int i=h[t];~i;i=ne[i])
        {
            int j=e[i];
            if(dist[j]>dist[t]+w[i])
            {
                dist[j]=dist[t]+w[i];
                if(!st[j])
                {
                    st[j]=true;
                    que.push(j);
                }
            }
        }
    }
}
signed main()
{
    memset(h,-1,sizeof h);
    scanf("%lld%lld",&m,&n);

    for(int i=1;i<=m;i++)
        for(int j=1;j<=m;j++)
        d[i][j]=-1;

    for(int i=1;i<=n;i++)
    {
        int x,y,c;
        scanf("%lld%lld%lld",&x,&y,&c);
        d[x][y]=c;
    }
    for(int i=1;i<=m;i++)
        for(int j=1;j<=m;j++)
    {
        if(d[i][j]!=-1)
        {
            for(int k=0;k<4;k++)
            {
                int x=i+dx[k];
                int y=j+dy[k];
                if(x<=0||x>m||y<=0||y>m)
                    continue;
                if(d[x][y]!=-1)
                {
                    if(d[x][y]==d[i][j])
                    {
                        add(x*m+y,i*m+j,0);
                    }else{
                        add(x*m+y,i*m+j,1);
                    }
                }
            }
        }else{
            vector<PII>v;
            for(int k=0;k<4;k++)
            {
                int x=i+dx[k];
                int y=j+dy[k];
                if(x<=0||x>m||y<=0||y>m)
                    continue;
                if(d[x][y]!=-1)
                v.push_back({x*m+y,d[x][y]});
                add(x*m+y,i*m+j,2);
                 add(i*m+j,x*m+y,2);
            }
            if(v.size()>1)
            {
                for(int i=0;i<v.size();i++)
                    for(int j=0;j<v.size();j++)
                {
                    if(i==j)
                        continue;
                    if(v[i].second!=v[j].second)
                    {
                        add(v[i].first,v[j].first,3);
                        add(v[j].first,v[i].first,3);
                    }else{
                         add(v[j].first,v[i].first,2);
                          add(v[i].first,v[j].first,2);
                    }
                }
            }
        }
    }
    
    spfa();

    if(dist[m*m+m]>=1e9)
        puts("-1");
        else
    cout<<dist[m*m+m];

	return 0;
}

还有,同样是转换成无向图建边的大佬的满分代码

题解 P3956 【棋盘】 - 恨妹不成穹 的博客 - 洛谷博客

题目中n的范围是1~1000,实际最多也就1000个点,所以可以使用dijkstra,

至于更加详细的建边过程在大佬博客里面

代码:文章来源地址https://www.toymoban.com/news/detail-429533.html

#include<bits/stdc++.h>
using namespace std;
bool f[1002];
int n,m,x[1002],y[1002],z[1002][1002],col[1002],sta,en,flag,s[1002];
void dj(int k)	
{
	s[k]=0;
	int maxn,t;
	for(int i=1;i<=m;i++)
	{
    	maxn=99999999;
    	for(int j=1;j<=m;j++)                 
    	{
        	if(f[j]==0&&s[j]<maxn)
       		{
            	maxn=s[j];
				t=j;
        	}
    	}
    	f[t]=1;
    	for(int j=1;j<=m;j++)
		{
			s[j]=min(s[t]+z[t][j],s[j]);
		}
	}
}
int main()
{
  	//freopen("chess.in","r",stdin);
  	//freopen("chess.out","w",stdout);
  	memset(z,1,sizeof(z));
  	memset(s,1,sizeof(s));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d%d",&x[i],&y[i],&col[i]);
		if(x[i]==1&&y[i]==1)
		{
			sta=i;
		}
		if(x[i]==n&&y[i]==n)
		{
			flag=1;
			en=i;
		}
	}
	if(flag==0)
	{
		en=m+1;
		x[en]=y[en]=n;
	}
	for(int i=1;i<m;i++)
	{
		for(int j=i+1;j<=m;j++)
		{
			if(abs(x[i]-x[j])+abs(y[i]-y[j])==1)
			{
				z[i][j]=z[j][i]=abs(col[i]-col[j]);
			}
			if(abs(x[i]-x[j])+abs(y[i]-y[j])==2)
			z[i][j]=z[j][i]=2+abs(col[i]-col[j]);
		}
	}
	if(flag==0)
	{
		for(int i=1;i<=m;i++)
		{
			if(abs(x[i]-x[en])+abs(y[i]-y[en])==1)
			{
				z[i][en]=z[en][i]=2;
			}
		}
		m++;
	}
	dj(sta); 
	if(s[en]<16843009)
	cout<<s[en];
	else
	cout<<-1;
	
	
	
	return 0;
}

到了这里,关于搜索?——P3956 [NOIP2017 普及组] 棋盘的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • #P0999. [NOIP2008普及组] 排座椅

    上课的时候总会有一些同学和前后左右的人交头接耳,这是令小学班主任十分头疼的一件事情。不过,班主任小雪发现了一些有趣的现象,当同学们的座次确定下来之后,只有有限的 DD 对同学上课时会交头接耳。 同学们在教室中坐成了 MM 行 NN 列,坐在第 ii 行第 jj 列

    2024年02月15日
    浏览(47)
  • [NOIP2009 普及组] 分数线划定#洛谷

    世博会志愿者的选拔工作正在 A 市如火如荼的进行。为了选拔最合适的人才,A 市对所有报名的选手进行了笔试,笔试分数达到面试分数线的选手方可进入面试。面试分数线根据计划录取人数的 150 % 150% 150% 划定,即如果计划录取 m m m 名志愿者,则面试分数线为排名第 m ×

    2024年01月17日
    浏览(41)
  • P1077 [NOIP2012 普及组] 摆花 题解

    小明的花店新开张,为了吸引顾客,他想在花店的门口摆上一排花,共 m m m 盆。通过调查顾客的喜好,小明列出了顾客最喜欢的 n n n 种花,从 1 1 1 到 n n n 标号。为了在门口展出更多种花,规定第 i i i 种花不能超过 a i a_i a i ​ 盆,摆花时同一种花放在一起,且不同种类的花

    2024年02月08日
    浏览(47)
  • #P1003. [NOIP2009普及组] 道路游戏

    小新正在玩一个简单的电脑游戏。 游戏中有一条环形马路,马路上有 nn 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接。小新以某个机器人工厂为起点,按顺时针顺序依次将这 nn 个机器人工厂编号为 1sim n1∼n,因为马路是环形的,所以第 nn 个机器人工厂和

    2024年02月15日
    浏览(37)
  • NOIP2013普及组复赛T4:车站分级

    题目链接:洛谷P1983 [NOIP2013 普及组] 车站分级 一条单向的铁路线上,依次有编号为 1 , 2 , … , n 1, 2, …, n 1 , 2 , …

    2024年02月08日
    浏览(35)
  • [NOIP2004 普及组] FBI 树 队列解法

    我们可以把由 0 和 1 组成的字符串分为三类:全 0 串称为 B 串,全 1 串称为 I 串,既含 0 又含 1 的串则称为 F 串。 FBI 树是一种二叉树,它的结点类型也包括 F 结点,B 结点和 I 结点三种。由一个长度为 $2^N$ 的 01 串 S 可以构造出一棵 FBI 树 T,递归的构造方法如下: 1. T 的根

    2024年02月07日
    浏览(94)
  • NOIP2003普及组复赛T2:数字游戏

    题目链接:NOIP2003普及组复赛T2 - 数字游戏 丁丁最近沉迷于一个数字游戏之中。这个游戏看似简单,但丁丁在研究了许多天之后却发觉原来在简单的规则下想要赢得这个游戏并不那么容易。游戏是这样的,在你面前有一圈整数(一共 n n n 个),你要按顺序将其分为 m m m 个部分

    2024年02月09日
    浏览(41)
  • P1093 [NOIP2007 普及组] 奖学金

    某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前 5 5 5 名学生发奖学金。期末,每个学生都有 3 3 3 门课的成绩:语文、数学、英语。先按总分从高到低排序,如果两个同学总分相同,再按语文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么

    2024年02月10日
    浏览(40)
  • P1046 [NOIP2005 普及组] 陶陶摘苹果

    陶陶家的院子里有一棵苹果树,每到秋天树上就会结出 1010 个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个 3030 厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。 现在已知 1010 个苹果到地面的高度,以及陶陶把手伸直的时候能够达到

    2023年04月27日
    浏览(33)
  • P1030 [NOIP2001 普及组] 求先序排列

    给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,且二叉树的节点个数 ≤8≤8)。 共两行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序排列。 共一行一个字符串,表示一棵二叉树的先序。 输入 #1 复制 输出 #1 复制

    2023年04月22日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包