zoukankan      html  css  js  c++  java
  • 【最短路】血色先锋军(scarlet) 解题报告

    问题来源

    BYVoid魔兽世界模拟赛

    【问题描述】

    巫妖王的天灾军团终于卷土重来,血色十字军组织了一支先锋军前往诺森德大陆对抗天灾军团,以及一切沾有亡灵气息的生物。孤立于联盟和部落的血色先锋军很快就遭到了天灾军团的重重包围,现在他们将主力只好聚集了起来,以抵抗天灾军团的围剿。可怕的是,他们之中有人感染上了亡灵瘟疫,如果不设法阻止瘟疫的扩散,很快就会遭到灭顶之灾。大领主阿比迪斯已经开始调查瘟疫的源头。原来是血色先锋军的内部出现了叛徒,这个叛徒已经投靠了天灾军团,想要将整个血色先锋军全部转化为天灾军团!无需惊讶,你就是那个叛徒。在你的行踪败露之前,要尽快完成巫妖王交给你的任务。
    军团是一个N行M列的矩阵,每个单元是一个血色先锋军的成员。感染瘟疫的人,每过一个小时,就会向四周扩散瘟疫,直到所有人全部感染上瘟疫。你已经掌握了感染源的位置,任务是算出血色先锋军的领主们感染瘟疫的时间,并且将它报告给巫妖王,以便对血色先锋军进行一轮有针对性的围剿。

    【输入格式】

    第1行:四个整数N,M,A,B,表示军团矩阵有N行M列。有A个感染源,B为血色敢死队中领主的数量。
    接下来A行:每行有两个整数x,y,表示感染源在第x行第y列。
    接下来B行:每行有两个整数x,y,表示领主的位置在第x行第y列。

    【输出格式】

    第1至B行:每行一个整数,表示这个领主感染瘟疫的时间,输出顺序与输入顺序一致。
    如果某个人的位置在感染源,那么他感染瘟疫的时间为0。

    【输入样例】

    5 4 2 3
    1 1
    5 4
    3 3
    5 3
    2 4

    【输出样例】

    3
    1
    3

    【数据说明】

    如下图,标记出了所有人感染瘟疫的时间以及感染源和领主的位置。

      1 2 3 4
    1 0 1 2 3
    2 1 2 3 3
    3 2 3 3 2
    4 3 3 2 1
    5 3 2 1 0
    1<=M,N<=500 1<=A,B<=M*N

    分析

    一道简单的单源最短路模型转换。既然是单源最短路,源点只能有一个,可是题目中有多个感染源,怎么解决呢?我们可以虚拟一个点,这个点与各个源点之间连边,边权为0,这样只需要把这个虚拟点初始时加入队列,就可以求出整张图的最短路了。这就是这个题目中值得着重理解的转化思路。但是我在实际代码中没有虚拟这一个点,而是直接把感染源加入队列,并把他的dist设为0,这样就和前面所说的思路是等价的了。借助这个思路,我在考试时AC了这题,下面是代码:

    /*
    ID: ringxu97
    LANG: C++
    TASK: scarlet
    SOLUTION: 最短路
    */
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<cstdlib>
    #include<algorithm>
    #include<vector>
    #include<stack>
    #include<queue>
    using namespace std;
    
    const int inf=0x3f3f3f3f;
    
    const int maxn=500+10;
    const int maxa=maxn*maxn;
    
    const int dx[]={0,0,0,1,-1};
    const int dy[]={0,1,-1,0,0};
    
    struct POINT//定义图中节点 
    {
    	int x,y;
    	POINT(int a,int b){x=a;y=b;}
    	POINT(){x=0;y=0;}
    }l[maxa],s[maxa];//l储存leader(领主)  s储存Source(感染源) 
    int N,M,A,B;
    int dist[maxn][maxn];//dist[i][j]表示传播到[i][j]所需最短时间 
    bool inq[maxn][maxn];
    queue<POINT>Q;
    
    void init()
    {
    	memset(inq,0,sizeof(inq));
    	for(int i=1;i<=N;++i)
    	for(int j=1;j<=M;++j)
    	{
    		dist[i][j]=inf;
    	}
    }
    
    void read()//读入数据 
    {
    	scanf("%d%d%d%d",&N,&M,&A,&B);
    	init();
    	for(int i=1;i<=A;++i)
    	{
    		scanf("%d%d",&s[i].x,&s[i].y);
    		dist[s[i].x][s[i].y]=0;
    		POINT tmp(s[i].x,s[i].y);
    		inq[s[i].x][s[i].y]=1;//初始化源点,并将其加入队列 
    		Q.push(tmp);
    	}
    	for(int i=1;i<=B;++i)
    	{
    		scanf("%d%d",&l[i].x,&l[i].y);
    	}
    }
    inline bool check(int i,int j)//检查是否在图内 
    {
    	return (1<=i && i<=N && 1<=j && j<=M);
    }
    void SPFA()//求最短路 
    {
    	while(!Q.empty())
    	{
    		POINT u=Q.front();Q.pop();
    		inq[u.x][u.y]=0;
    		for(int k=1;k<=4;++k)if(check(u.x+dx[k],u.y+dy[k]))
    		{
    			POINT v(u.x+dx[k],u.y+dy[k]);
    			if(dist[v.x][v.y]>dist[u.x][u.y]+1)
    			{
    				dist[v.x][v.y]=dist[u.x][u.y]+1;
    				if(!inq[v.x][v.y])
    				{
    					Q.push(v);
    					inq[v.x][v.y]=1;
    				}
    			}
    		}
    		
    	}
    }
    void print()//打印方案 
    {
    	for(int i=1;i<=B;++i)
    	{
    		printf("%d
    ",dist[l[i].x][l[i].y]);
    	}
    }
    
    int main()
    {
        freopen("scarlet.in", "r", stdin);
        freopen("scarlet.out", "w", stdout);
        read();
        SPFA();
        print();
    	return 0;
    }
  • 相关阅读:
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    OA办公系统 Springboot Activiti6 工作流 集成代码生成器 vue.js 前后分离 跨域
    java企业官网源码 自适应响应式 freemarker 静态引擎 SSM 框架
    java OA办公系统源码 Springboot Activiti工作流 vue.js 前后分离 集成代码生成器
    springcloud 项目源码 微服务 分布式 Activiti6 工作流 vue.js html 跨域 前后分离
    java 视频播放 弹幕技术 视频弹幕 视频截图 springmvc mybatis SSM
    最后阶段总结
    第二阶段学习总结
    第一阶段学习总结
  • 原文地址:https://www.cnblogs.com/ringxu97/p/scarlet.html
Copyright © 2011-2022 走看看