蕞短鹭(artskjid) (⭐通信题/模拟⭐)

题面(过于冗长,主要是对通信题的一些解释)

在这里插入图片描述

题解

1.通信题什么意思

并不是两个程序同时跑。

而是你写两个不能单独运行的子程序,然后由评测方调用,检查是否通过数据点。

通信题一般会给你很多函数,有些是你可以不用手写定义就使用的函数(一般在“有效文件名.h”里定义了,你得在代码里加上它的头文件,用""而不是<>),这是第一类,有些是你需要定义其内容的函数(这类函数将被评测方调用,用以检查是否通过),这是第二类。

所以,形象地说,你要写的算法部分得被拆分到各个第二类函数里,适应题目告诉你的调用顺序。你的两个程序是死的,它们没有主函数,只会在被评测方调用时“激活”特定的函数并运行。此时你可能就不得不把算法中的一些循环展开,多加些 if, else 把算法拆分到不同函数中 😐。

因此,大多通信题都可以算是模拟题了吧。

2.此题题解

它要求最短路,那我们就跑个Dijkstra好了。算法过程应该都清楚:

  1. 找到目前没计算过的距离起点最近的转移点。
  2. 更新邻接点的最短路。
  3. 重复此过程直到所有点都计算过。

此时的局限是,A 和 B 任一方都不知道所有的边,只知道一部分。其实这个很好办,对于第二步,我们就利用自己知道的边转移就行了,然后为了保证第一步得到的是正确的转移点和最短路,需要 A 和 B 进行一次交流。

先向对方发送自己计算的转移点最短路长度,然后当一方知道了对方的最短路长度,就可以比较得出谁的转移点是正确的。

比较得出自己的转移点更优的话,需要向对方发送自己的转移点编号,因为对方此时只知道你的更优,以及转移点最短路长度是多少,但是不知道转移点具体的编号。

比较得出对方转移点更优的话,则等待对方发送的编号。

传输的数据长度是 n ( log ⁡ n + 2 ∗ log ⁡ ( w ∗ n ) ) n(\log n+2*\log (w*n)) n(logn+2log(wn)) 的,长度会超过 58000。我们加一个小优化:每次发送最短路长度 - 上一个转移点的最短路。由 Dijkstra 算法的性质可以证明这个数是不超过 w 的数据范围的,那么数据长度就优化到了 n ( log ⁡ n + 2 ∗ log ⁡ w ) n(\log n+2*\log w) n(logn+2logw) ,刚好卡到 58000 😓.

CODE

实现

由于 A 和 B 的代码类似,就拿 A 说吧。

我们会在 InitA() 函数中知道 n,m 和边的信息,因此在这个函数中初始化算法,我们把要用到的信息存到全局变量中:

InitA(...) {
	记录 n,m;
	存边, 建图;
	更新 0 号点的邻点最短路;
	last_ans = 0;
	开始 dijkstra:
		交流: 发送转移点最短路...
}

然后呢?我们发现接收函数是外面的 ReceiveA() ,此时就不得不结束 InitA() 了啊,因此我们得多用一些变量记录算法流程,当前接收信息的目的,接收的完整度等。在 ReceiveA() 中我们得判断当前接收的信息是否完整(因为每次只有一个 bool ,得接收多次),若已100%接收,则把下一次接收信息之前的操作都做完,退出函数(等待下一次被调用)。

还是比较考验模拟能力的。

View Code

为了防止变量重名编译错误,需要把全局变量等放进空 namespace 里。

A.hB.h 中是对各个函数的声明。

A.cpp

#include "A.h"
#include <bits/stdc++.h>
using namespace std;
namespace {
	#define MAXN 2005
	#define DB double
	#define LL long long
	#define ENDL putchar('\n')
	#define lowbit(x) (-(x) & (x))
	int n,m,s,o,k;
	struct it{
		int v,w;it(){v=w=0;}
		it(int V,int W){v=V;w=W;}
	};
	vector<it> g[MAXN];
	int dp[MAXN];
	int tre[MAXN<<2],M;
	int bing(int a,int b) {return dp[a] < dp[b] ? a:b;}
	void maketree(int n) {M=1;while(M<n+2)M<<=1;}
	void addtree(int x,int y) {
		int s = M+x;tre[s] = y; s >>= 1;
		while(s) tre[s] = bing(tre[s<<1],tre[s<<1|1]),s >>= 1;
	}
	int findall() {return tre[1];}
	int CNT = 0,ctnm = 0,recnm = 0;
	int flag = 0;
	void sendnmA(int x,int bt) {
		for(int i = bt-1;i >= 0;i --) {
			bool tmp = (x & (1<<i));
			SendA(tmp);
		}return ;
	}
	int t,las = 0;
	void calcu() {
		for(int i = 0;i < (int)g[t].size();i ++) {
			int y = g[t][i].v,w = g[t][i].w;
			if(dp[t] + w < dp[y]) {
				dp[y] = dp[t] + w;
				addtree(y,y);
			}
		}
		addtree(t,0);
		CNT ++;
		flag = 1;
		t = findall();
		if(CNT >= n || !t) {flag = -1;return ;}
		sendnmA(min(511,dp[t]-las),9);
		return ;
	}
}
void ReceiveA(bool x) {
	recnm <<= 1;recnm += x;
	ctnm ++;
	if(flag == 1 && ctnm >= 9) {
		if(recnm+las >= dp[t]) {
			sendnmA(t,11);
			las = dp[t];
			ctnm = recnm = 0;
			calcu();
		}
		else {
			flag = 0;
			las = recnm + las;
			ctnm = recnm = 0;
		}
		return ;
	}
	if(flag == 0 && ctnm >= 11) {
		t = recnm;dp[t] = las;
		ctnm = recnm = 0;
		calcu();
		return ;
	}
	return ;
}
void InitA(int N, int M, vector < int > U, vector < int > V, vector < int > W) {
	n = N;m = M;
	for(int i = 1;i <= m;i ++) {
		s = U[i-1]+1; o = V[i-1]+1; k = W[i-1];
		g[s].push_back(it(o,k));
		g[o].push_back(it(s,k));
	}
	maketree(n);
	for(int i = 0;i <= n;i ++) dp[i] = 0x7f7f7f7f;
	dp[1] = 0;t = 1;las = 0;
	calcu();
	return ;
}
vector < int > Answer() {
	vector < int > ans;
	for(int i = 1;i <= n;i ++) {
		ans.push_back(dp[i]);
	}
	return ans; 
}

B.cpp

#include "B.h"
#include <bits/stdc++.h>
using namespace std;
namespace {
	#define MAXN 2005
	#define DB double
	#define LL long long
	#define ENDL putchar('\n')
	#define lowbit(x) (-(x) & (x))
	int n,m,s,o,k;
	struct it{
		int v,w;it(){v=w=0;}
		it(int V,int W){v=V;w=W;}
	};
	vector<it> g[MAXN];
	int dp[MAXN];
	int tre[MAXN<<2],M;
	int bing(int a,int b) {return dp[a] < dp[b] ? a:b;}
	void maketree(int n) {M=1;while(M<n+2)M<<=1;}
	void addtree(int x,int y) {
		int s = M+x;tre[s] = y; s >>= 1;
		while(s) tre[s] = bing(tre[s<<1],tre[s<<1|1]),s >>= 1;
	}
	int findall() {return tre[1];}
	int CNT = 0,ctnm = 0,recnm = 0;
	int flag = 0;
	void sendnmB(int x,int bt) {
		for(int i = bt-1;i >= 0;i --) {
			bool tmp = (x & (1<<i));
			SendB(tmp);
		}return ;
	}
	int t,las = 0;
	void calcu() {
		for(int i = 0;i < (int)g[t].size();i ++) {
			int y = g[t][i].v,w = g[t][i].w;
			if(dp[t] + w < dp[y]) {
				dp[y] = dp[t] + w;
				addtree(y,y);
			}
		}
		addtree(t,0);
		CNT ++;
		flag = 1;
		t = findall();
		if(CNT >= n || !t) {flag = -1;return ;}
		sendnmB(min(511,dp[t]-las),9);
		return ;
	}
}
void ReceiveB(bool x) {
	recnm <<= 1;recnm += x;
	ctnm ++;
	if(flag == 1 && ctnm >= 9) {
		if(recnm+las > dp[t]) {
			sendnmB(t,11);
			las = dp[t];
			ctnm = recnm = 0;
			calcu();
		}
		else {
			flag = 0;
			las = recnm + las;
			ctnm = recnm = 0;
		}
		return ;
	}
	if(flag == 0 && ctnm >= 11) {
		t = recnm;dp[t] = las;
		ctnm = recnm = 0;
		calcu();
		return ;
	}
	return ;
}
void InitB(int N, int M, vector < int > U, vector < int > V, vector < int > W) {
	n = N;m = M;
	for(int i = 1;i <= m;i ++) {
		s = U[i-1]+1; o = V[i-1]+1; k = W[i-1];
		g[s].push_back(it(o,k));
		g[o].push_back(it(s,k));
	}
	maketree(n);
	for(int i = 0;i <= n;i ++) dp[i] = 0x7f7f7f7f;
	dp[1] = 0;t = 1;las = 0;
	calcu();
	return ;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值