zoukankan      html  css  js  c++  java
  • [Luogu]P2302 loidc,跑起来

    [Luogu]P2302 loidc,跑起来

    扯淡

    这个游戏让我想起了小学和同学玩"抓人",有过游戏经验的同学都知道,我们要找一个地方,可以和"追捕者"一直转圈圈,比如有东西两个楼道的教学楼就是不错的地方。

    题意简化

    现在有两个人小(L)(loidc)和小(C)(cony),都处于一张无向联通图上的某个节点(给出他们所在的节点)而且这张图不存在三元环,每次一个人每回合可以走一步,小(L)尽量避免与小(C)相遇,而小(C)则尽量想让两个人相遇(有没有一点点像狗血的某种故事.......)两个人都选择最佳策略,问最终会不会相遇,如果相遇,那么最少用几回合?。

    解题思路

    你会说,我一开头说的是废话,但是事实则不然.......这道题和上面的抓人游戏类似。

    抽象到题目里面,什么地方是可以和"追捕者"一直转圈圈的?不难想,是环上面。一开始我很费解,为什么给出这张图不含三元环,后来我思考了一下,三元环其实并不能满足一直转圈圈的性质,题解中的第一篇就讲到了这一点。

    那最优策略就是小(L)就要赶紧跑到环上面,小(C)要赶紧堵住小(L),阻止小(C)到环上面。

    (L)为了尽快跑到环上面,他选择跑到一个环上面的点(但是并非是距离自己最近的,想一想为什么),假设这个点为(P),那么小(L)怎么办?显然小(L)被迫的也要跑到(P)点,不然怎么阻止小(L)上到环上面去?所以解法逐渐浮现在我们眼前。

    ——————————————————————分割线——————————————————————

    上面的是对于题目的分析,要是你已经分析过了可以直接看下面的做法

    首先我们要找环啊,于是(tarjan)是首选,然后我们要确定“尽快跑到环上的距离小(L)最近的一点所用的时间”,于是我们需要(Dijkstra)最短路算法,计算一下小(L)到所有点的最短距离,然后还需要计算小(C)到每一个点的最短距离,然后枚举每一个点,先判断其是否在一个环上面,然后判断一下小(L)到达它的时间是否小于小(C)到达它的时间,如果存在任意一个这样的点,输出"No"。

    如果不存在这个点怎么办?

    可以把小(L)和小(C)的行走过程分为(x)个回合,先让小(L)(x)个回合,那么他最终会在一个点停下来。无论这个点是哪个点,实际上只需要计算小(C)到这个点的最短路径即可,同时请想,假若小(L)到达这个点所用的时间大于小(C)到这个点的时间,那小(L)显然无法到达这个点,所以最后的答案会是满足距离小(C)最远的且满足小(L)到这个点的距离小于小(C)到这个点的距离的点。

    ————————————————————end————————————————————

    以上就是关于这道题的做法!

    贴出代码

    #include <bits/stdc++.h>
    using namespace std;
    #define INF 100000000
    const int MAXN = 6000, MAXM = 30005;
    int n,m,s,t,tot = 0,cnt = 0,now = 0,z = 0;
    int dfn[MAXN],low[MAXN],siz[MAXN],color[MAXN];
    int tack[MAXN],vis[MAXN],book[MAXN];//tarjan算法缩点常用数组
    int start[MAXN],tag[MAXN],dis[MAXN],D1[MAXN],D2[MAXN];
    //D1为小L到各点的距离,D2为小C到各点的距离,tag表示是否在环上
    
    struct Edge {
    	int next,to;
    } edge[MAXM];
    
    struct data {
    	int sum,id;
    	bool operator <(const data& fz) const {
    		return fz.sum < sum;
    	}
    };
    
    priority_queue <data> q;//上面是Dijkstra要用到的东西
    
    void add(int from,int to);
    void tarjan(int x,int fa);
    void Dijkstra(int S);
    
    int main()
    {
    	cin >> n >> m >> s >> t;
    	for(int i = 1 ; i <= m ; i ++)
    	{
    		int u, v;
    		cin >> u >> v;
    		add(u,v);
    		add(v,u);	
    	}
    	for(int i = 1 ; i <= n ; i ++)
    		if(!dfn[i])tarjan(i,i);//tarjan
    	
    	for(int i = 1 ; i <= n ; i ++)
    		if(siz[color[i]] > 1)tag[i] = 1;//一个点单独成环没用...
    	Dijkstra(s);
    	for(int i = 1 ; i <= n ; i ++)D1[i] = dis[i];
    	Dijkstra(t);//跑两遍Dijkstra
    	int M = -1000000;
    	for(int i = 1 ; i <= n ; i ++)D2[i] = dis[i];
    	int flag = 0;
    	for(int i = 1 ; i <= n ; i ++)
    		if(D1[i] < D2[i])
    		{
    			M = max(M,D2[i]);
    			if(tag[i] )flag = 1;
    		}
    	if(flag == 1)cout <<"NO
    ";
    	else cout << M << endl;
    	return 0;
    }
    
    void add(int from,int to)
    {
    	cnt ++;
    	edge[cnt].to = to;
    	edge[cnt].next = start[from];
    	start[from] = cnt;
    	return ;//前向星加边
    }
    
    void tarjan(int x,int fa)//标准的tarjan即可
    {
    	dfn[x] = low[x] = ++now;
    	tot ++ , vis[tot] = x;
    	book[x] = 1;
    	for(int i = start[x] ; i ; i = edge[i].next)
    	{
    		int to = edge[i].to;
    		if(to == fa)continue;//无向边,防止反复横跳
    		if(!dfn[to])
    		{
    			tarjan(to,x);
    			low[x] = min(low[x],low[to]);
    		}
    		else if(book[to]) low[x] = min(low[x],dfn[to]);
    	}
    	if(dfn[x] == low[x])
    	{
    		z ++;
    		while(vis[tot + 1] != x && tot > 0)
    		{
    			color[vis[tot]] = z;
    			siz[z] ++;
    			book[tot] = 0;
    			tot --;
    		}
    	}
    	return ;
    }
    
    void Dijkstra(int S)//Dijkstra求最短路即可
    {
    	
    	for(int i = 1 ; i <= n ; i ++)dis[i] = INF;
    	dis[S] = 0;
    	q.push(data {dis[S],S});
    	memset(book,0,sizeof(book));
    	book[S] = 1;
    	while(!q.empty())
    	{
    		data X = q.top();
    		q.pop();
    		if(X.sum != dis[X.id])continue;
    		book[X.id] = 1;
    		int x = X.id;
    		for(int i = start[x] ; i ; i = edge[i].next)
    		{
    			int to = edge[i].to;
    			if(dis[to] > dis[x] + 1)
    			{
    				dis[to] = dis[x] + 1;
    				if(!book[to])q.push(data {dis[to],to});
    			}
    		}
    	}
    	return ;
    }
    

    这个题目没有很多的细节,但是注意写对基础算法!

  • 相关阅读:
    java — 排序算法
    sping框架(3)— 使用spring容器
    java — 线程池
    一致性哈希算法(consistent hashing)
    linux进程调度
    滑动窗口协议
    final和static关键字
    II 3.1 连接到服务器
    intel-hadoop/HiBench流程分析----以贝叶斯算法为例
    Android开发学习之路--基于vitamio的视频播放器(二)
  • 原文地址:https://www.cnblogs.com/MYCui/p/13916652.html
Copyright © 2011-2022 走看看