[CSP-S模拟测试]:maze(二分答案+最短路)

题目传送门(内部题88)


输入格式

第一行两个数$n,m$。
第二行四个数$sx,sy,tx,ty$。分别表示起点所在行数、列数,终点所在行数、列数。
接下来$n$行,每行$m$个数,描述迷宫。
最后一行一个正实数$s$。


输出格式

输出答案$k$,四舍五入保留$3$位小数。(评测时开启逐行比较模式)


样例

样例输入:

4 4
1 1 4 4
0 0 1 1
1 0 0 0
0 0 1 0
0 0 0 0
5

样例输出:

0.667


数据范围与提示

对于$30\%$的数据:$n,m\leqslant 10$
对于另$10\%$的数据:保证从起点到终点有且只有一条不重复经过同一个点的路径
对于$100\%$的数据:$n,m\leqslant 100,0<s\leqslant 10^5$


题解

考虑为什么决策有单调性:

  $\alpha.$如题,显然只有一组解,所以决策一定单调。

  $\beta.$如果$k>1$,那么随着其不断增大,横向走肯定不断增加,直到极限;反之同理。

所以考虑二分答案$+$最短路就好了。

注意题目中说$s$是实数,即有可能是小数。

时间复杂度:$\Theta(nm\log nm\times log s)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
const double eps=1e-5;
struct rec{int nxt,to;bool w;}e[100000];
int head[10001],cnt;
int n,m;
int sx,sy,tx,ty;
bool Map[102][102];
int tim[102][102],t;
double dis[10001];
bool vis[10001];
double s;
priority_queue<pair<double,int>,vector<pair<double,int>>,greater<pair<double,int>>>q;
void add(int x,int y,bool w)
{
	e[++cnt].nxt=head[x];
	e[cnt].to=y;
	e[cnt].w=w;
	head[x]=cnt;
}
void Dij(int x,double w)
{
	dis[x]=0.0;
	q.push(make_pair(0.0,x));
	while(!q.empty())
	{
		int flag=q.top().second;q.pop();
		if(vis[flag])continue;
		vis[flag]=1;
		for(int i=head[flag];i;i=e[i].nxt)
		{
			double d=(e[i].w)?w:1.0;
			if(dis[e[i].to]>dis[flag]+d)
			{
				dis[e[i].to]=dis[flag]+d;
				q.push(make_pair(dis[e[i].to],e[i].to));
			}
		}
	}
}
bool judge(double mid)
{
	for(int i=1;i<=t;i++)
	{
		vis[i]=0;
		dis[i]=1000000000.0;
	}
	Dij(tim[sx][sy],mid);
	if(dis[tim[tx][ty]]<s)return 1;
	return 0;
}
int main()
{
	scanf("%d%d%d%d%d%d",&n,&m,&sx,&sy,&tx,&ty);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			scanf("%d",&Map[i][j]);
			tim[i][j]=++t;
		}
	for(int i=0;i<=n+1;i++)Map[i][0]=Map[i][m+1]=1;
	for(int i=0;i<=m+1;i++)Map[0][i]=Map[0][n+1]=1;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		{
			if(Map[i][j])continue;
			if(!Map[i-1][j]){add(tim[i][j],tim[i-1][j],1);add(tim[i-1][j],tim[i][j],1);}
			if(!Map[i+1][j]){add(tim[i][j],tim[i+1][j],1);add(tim[i+1][j],tim[i][j],1);}
			if(!Map[i][j-1]){add(tim[i][j],tim[i][j-1],0);add(tim[i][j-1],tim[i][j],0);}
			if(!Map[i][j+1]){add(tim[i][j],tim[i][j+1],0);add(tim[i][j+1],tim[i][j],0);}
		}
	scanf("%lf",&s);
	double lft=0.0,rht=s;
	while(rht-lft>eps)
	{
		double mid=(lft+rht)/2;
		if(judge(mid))lft=mid;
		else rht=mid;
	}
	printf("%.3lf",lft);
	return 0;
}

rp++

posted @ 2019-10-26 16:52  HEOI-动动  阅读(208)  评论(0编辑  收藏  举报