hihoCoder 第38周 二分答案+BFS

题意 在这个游戏里面,海域是N个战略点(编号1..N)组成,其中红色的点表示有敌人驻扎,猫头像的的点表示该地图敌军主力舰队(boss)的驻扎点,虚线表示各个战略点之间的航线(无向边)
在游戏中要从一个战略点到相邻战略点需要满足一定的条件,即需要舰队的索敌值大于等于这两点之间航线的索敌值需求。
由于提高索敌值需要将攻击机、轰炸机换成侦察机,舰队索敌值越高,也就意味着舰队的战力越低。
另外在每一个战略点会发生一次战斗,需要消耗1/K的燃料和子弹。必须在燃料和子弹未用完的情况下进入boss点才能与boss进行战斗,所以舰队最多只能走过K条航路。
现在Nettle想要以最高的战力来进攻boss点,所以他希望能够找出一条从起始点(编号为1的点)到boss点的航路,使得舰队需要达到的索敌值最低,并且有剩余的燃料和子弹。
特别说明:两个战略点之间可能不止一条航线,两个相邻战略点之间可能不止一条航线。保证至少存在一条路径能在燃料子弹用完前到达boss点。

思路 考虑到直接做FS,有这个索敌值限制确实不好做。但是,一旦确定了索敌值,那么超过这个值得边可以认为没有,那么这个题就是非常基础的BFS。因此我们想到可以枚举索敌值~然后,枚举的话,自然希望二分答案(当然这个专题就是二分嘛~)。把能否到达T作为因变量,索敌值作为自变量,很显然,这是非递减函数,可以二分~复杂度可以接受~

#include <stdio.h>
#include <cstring>
#include <queue>
#include <map>
#include <iostream> 
using namespace std;
const int maxn = 10005;
const int maxm = 100005;
const int maxw = 1000000;
typedef pair<int,int> PII;
#define fi first
#define se second
#define MP make_pair 

int n,m,k,t;
struct Edge{
	int u,v,c,next;
	Edge(int u=0,int v=0,int c=0,int next = -1):u(u),v(v),c(c),next(next){
		
	}
	void set(int u=0,int v=0,int c=0,int next = -1){
		this->u = u;
		this->v = v;
		this->c = c;
		this->next = next;
	}
}edge[maxm<<1];
int g[maxn];

int addEdge()
{
	for(int i=0;i<m;i++)
	{
		int u,v,c;
		scanf("%d%d%d",&u,&v,&c);
		//cout<<g[u]<<endl<<g[v]<<endl<<endl;
		edge[i<<1].set(u,v,c,g[u]);
		edge[(i<<1)|1].set(v,u,c,g[v]);
		g[u] = i<<1;
		g[v] = (i<<1)|1;
		//cout<<g[u]<<endl<<g[v]<<endl<<endl;
	}
}

int init()
{
	memset(g,-1,sizeof(g));
}

queue<PII> q;
int mark[maxn];
bool bfs(int limit)
{
	while(q.size()!=0)
		q.pop();
	memset(mark,0,sizeof(mark));
	q.push(MP(1,0));
	while(q.size()!=0)
	{
		PII tmp = q.front();
		q.pop();
//		cout<<tmp.fi<<endl;
		if(tmp.se >= k)
			return 0;
		for(int e=g[tmp.fi];e!=-1;e=edge[e].next)
		{
			if(edge[e].c > limit)
				continue;
			if(edge[e].v == t)
			{
				return 1;
			}
			if(mark[edge[e].v] == 1)
				continue;
			mark[edge[e].v] = 1;
			q.push(MP(edge[e].v,tmp.se+1));
		}
	}
	return 0;
}

int main()
{
	scanf("%d%d%d%d",&n,&m,&k,&t);
	int i,j;
	init();
	addEdge();
	int l,r,mid;
	int ans = 0;
	l = 1;
	r = maxw+1;
	while(l < r)
	{
		mid = (l+r)/2;
	//	cout<<l<<endl<<r<<endl<<mid<<endl<<endl; 
		if(bfs(mid))
		{
			r = mid;
			ans = mid;
		}
		else
		{
			l = mid + 1;
		}
	}
	printf("%d\n",ans);
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值