CCF 区块链 201912-4 5218ms

点击前往试题目录:https://blog.csdn.net/best335/article/details/99550556

题目描述

在这里插入图片描述

解题思路

题意简单清晰:

  • 总共不超过500个节点,编号1~n。
  • 每个节点各自维护一条主链,初始时每个链的长度为1,值为0,最大长度为500。
  • 节点间共有m条相互可达的无向路径。
  • 更新策略:
    • 主动更新:
      • 输入a b c
    • 被动更新:
      • 相邻节点更新后经过传输延时t后
      • 相邻接点主链长度更长 或者 两条链长度相同且相邻节点尾块块号更小
  • 有更新延时t,不超过1000。
  • 每次更新可以看做是做一次关于当前时间b+传输延时t的更新。
  • 有两种操作:
    • 更新主链:
      • 该行格式为:a b c
      • 格式解释:更新a节点在b时刻向其主链添加块号c
      • 注意:|c|<109
    • 查询主链:该行格式为:a b
      • 格式解释:查询在b时刻a节点的主链
      • 输出格式:a节点主链长度[空格]顺序输出主链块号,每个块号中间用空格相隔

仔细审题之后,发现这道题涉及一点图的BFS以及SPFA。

定义:
转折点:任意相邻两行b不同时的第二行的b为转折时间,简称转折点

决策:

  • 使用vector G[501]建立无向图

  • 使用vector Links[501]维护转折点的实时主链

  • 使用unordered_map<int, unordered_map<int,vector > > F
    维护临时主链<时间,<节点,节点更新时的临时主链> >

  • unordered_map<int, vector > tmpSearch
    维护转折点前的查询队列<查询时间,查询节点队列>

  • unordered_map<int, unordered_map<int, int> > tmpUpdate
    维护转折点前的更新队列<更新时间,<更新节点,更新块号> >

  • 每次在转折点的时刻或所有输入结束时做如下操作:

    • 按队列时间顺序接收和更新所有转折点之前的主链
    • 处理转折点之前的查询
    • 处理转折点之前的更新

博主精力有限,暂不深究未满分原因,以上解题思路希望对你们有帮助。
博主精力有限,暂不深究未满分原因,以上解题思路希望对你们有帮助。
博主精力有限,暂不深究未满分原因,以上解题思路希望对你们有帮助。

以下代码需要你静下心来阅读

70分代码

备注:代码底部有测试数据

#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<unordered_map>
#include<unordered_set>
#include<string>
using namespace std;

vector<int> G[501];//图
vector<int> Links[501];//主链
set<int> Q;//更新时间点队列索引
set<int>::iterator itQ;
unordered_map<int, unordered_map<int,vector<int> > > F;//更新时间点队列
unordered_map<int, unordered_map<int,vector<int> > >::iterator itF;
int n,m,t,k,u,v,a,b,c;//题意参数

set<int> TS,TU;//TS:tempsearch查询队列索引  TU:tempUpdate更新队列索引
set<int>::iterator itTS,itTU;
unordered_map<int, vector<int> > tmpSearch;//查询队列
unordered_map<int, vector<int> >::iterator itTmpS;
unordered_map<int, unordered_map<int, int> > tmpUpdate;//更新队列
unordered_map<int, unordered_map<int, int> > ::iterator itTmpU;

void enque(const int& time,const int& point){//标记time时刻point节点将要更新
	unordered_map<int, unordered_map<int,vector<int> > >::iterator it = F.find(time);
	if(it == F.end()){
		Q.insert(time);
		unordered_map<int,vector<int> > M;
		M.insert(pair<int,vector<int> >(point,vector<int>(Links[point])));
		F.insert(pair<int,unordered_map<int,vector<int> > >(time,M));
	}
	else{
		unordered_map<int, vector<int> >::iterator itM = it->second.find(point);
		if (itM == it->second.end()) {
			it->second.insert(pair<int, vector<int> >(point, vector<int>(Links[point])));
		}
		else {
			const vector<int>& vM = itM->second;
			int n1 = Links[point].size(), n2 = vM.size();
			if (n1 > n2 || n1 == n2&&Links[point].back() < vM.back()) {
				itM->second = vector<int>(Links[point]);
			}
		}
	}
}

void receiveChain() {//接收查询或更新前的主链  这个函数有点绕
	int timeQ = Q.empty() ? ::b : 0, timeT, flagQ=0, b = TS.empty()? ::b : *TS.begin();
	do {
		while(!TU.empty()&& (timeT = *(itTU = TU.begin())) < timeQ){//更新timeQ时间点前的主链信息 注意timeQ的取值 为了复用外围嵌套了一个do while循环
			const unordered_map<int,int>& M = tmpUpdate.find(timeT)->second;
			for (unordered_map<int,int>::const_iterator itM = M.begin(); itM != M.end(); ++itM){
				Links[itM->first].emplace_back(itM->second);
				enque(timeT + t, itM->first);
			}
			TU.erase(itTU);
			tmpUpdate.erase(timeT);
		}
		if (flagQ == 1) {//如果不是第一次循环 更新邻接点主链信息
			const unordered_map<int,vector<int> >& M = F.find(timeQ)->second;
			for (unordered_map<int,vector<int> >::const_iterator itM = M.begin(); itM != M.end(); ++itM) {
				const int& v = itM->first;
				const vector<int>& link = itM->second;
				for (int i = 0, ni = G[v].size(), n1, n2; i<ni; ++i) {
					n1 = link.size(), n2 = Links[G[v][i]].size();
					if (n1<n2 || n1 == n2&&link.back() >= Links[G[v][i]].back()) continue;

					Links[G[v][i]] = link;
					enque(t + timeQ, G[v][i]);
				}
			}
			F.erase(timeQ);
			Q.erase(itQ);
			continue;
		}
		flagQ = 1;
	} while (!Q.empty() && (timeQ = *(itQ = Q.begin())) <= b);
}

void outputChain() {//输出所有转折时间点之前待查询的节点
	for (itTS = TS.begin(); itTS != TS.end();++itTS) {
		itTmpS = tmpSearch.find(*itTS);
		const vector<int>& V = itTmpS->second;
		itTmpU = tmpUpdate.find(itTmpS->first);
		for (int i = 0, ni = V.size(), link_length, link_value, link_flag; i<ni; ++i) {
			link_length = Links[V[i]].size();
			link_flag = 0;
			if (itTmpU != tmpUpdate.end()) {
				const unordered_map<int, int>& M = itTmpU->second;
				unordered_map<int, int>::const_iterator itM = M.find(V[i]);
				if (itM != M.end()) {
					++link_length;
					link_flag = 1;
					link_value = itM->second;
				}
			}
			cout << link_length;
			for (int j = 0, nj = Links[V[i]].size(); j<nj; ++j) {
				cout << ' ' << Links[V[i]][j];
			}
			if (link_flag == 1) {
				cout << ' ' << link_value;
			}
			cout << endl;
		}
	}
	tmpSearch.clear();
	TS.clear();
}

void updateChain() {//更新主链
	for(itTmpU=tmpUpdate.begin();itTmpU!=tmpUpdate.end();++itTmpU){
		const unordered_map<int,int>& M = itTmpU->second;
		const int & timeU = itTmpU->first;
		for (unordered_map<int, int>::const_iterator itM = M.begin(); itM != M.end(); ++itM) {
			Links[itM->first].emplace_back(itM->second);
			enque(timeU + t, itM->first);
		}
	}
	tmpUpdate.clear();
	TU.clear();
}

void solve(){
	receiveChain();
	outputChain();
	updateChain();
}

int main(){
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin>>n>>m;
	for(int i=0;i<m;++i){
		cin>>u>>v;
		G[u].emplace_back(v);
		G[v].emplace_back(u);
	}
	for (int i = n; i > 0; --i) {
		Links[i].emplace_back(0);
	}

	cin>>t>>k;
	string s;
	for(int i=0,j,nj,lastTaskId=1,xk=k-1,type;i<k;++i){
		cin>>a>>b,type=-1;
		getline(cin,s);
		//以下直到空行区域内判断该输入行有几个数字 type==-1?两个数字:三个数字
		j=0,nj = s.size();
		while(j<nj&&s[j]==' ') ++j;
		bool isNegative = j<nj&&s[j]=='-'&&++j>0;//判断负数 如果是负数自加索引指针j
		if(j<nj&&isdigit(s[j])){
			c=0;
			type=0;
			while(j<nj&&isdigit(s[j])){
				c=c*10+(s[j]-'0');
				++j;
			}
			if(isNegative) c=-c;
		}

		if(b!=lastTaskId){//转折点
			solve();
		}
		
		if(type==-1){//两个数 放入查询队列
			if ((itTmpS = tmpSearch.find(b)) == tmpSearch.end()) {
				vector<int> v(1,a);
				tmpSearch.insert(pair<int, vector<int> >(b,v));
				TS.insert(b);
			}
			else {
				itTmpS->second.emplace_back(a);
			}
		}
		else{//三个数  放入更新队列
			if((itTmpU=tmpUpdate.find(b))==tmpUpdate.end()){
				unordered_map<int,int> M;
				M.insert(pair<int,int>(a,c));
				tmpUpdate.insert(pair<int,unordered_map<int,int> >(b,M));
				TU.insert(b);
			}
			else{
				itTmpU->second.insert(pair<int,int>(a,c));
			}
		}
		
		if(i==xk&&!tmpSearch.empty()){//转折点
			solve();
		}
		lastTaskId=b;
	}
	return 0;
}
/*
5 10
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
1 27
1 1 1
2 1 2
3 1 3
4 1 4
5 1 5
1 1
2 1
3 1
4 1
5 1
1 2
2 2
3 2
4 2
5 2
1 10 10
2 11 9
1 11
2 11
3 11
4 11
5 11
1 12
2 12
3 12
4 12
5 12


15 13
1 2
2 3
3 4
4 5
1 6
6 7
7 8
8 9
1 10
10 11
11 12
12 13
14 15
6 28
1 1 1
1 2 2
1 6
2 7
13 7
9 7
5 7
3 14
8 14
5 14
11 14
9 25
5 25
13 25
9 29 3
5 29 4
13 29 5
1 53
2 59 6
2 59
1 1000
3 1000
8 1000
9 1000
10 1000
13 1000
14 1000
15 1000
*/

时间压力测试代码

注意在enque函数加入如下代码限制主链长度不超过500
输出时记得输出到文件,输出到控制台时耗时高很多。
测试时时耗大概:5000ms

#include<iostream>
#include<vector>
#include<map>
#include<set>
#include<unordered_map>
#include<unordered_set>
#include<string>

#define DEBUG 1
#ifdef DEBUG
	#include<fstream>
	#include<ctime>
	std::ofstream LOG("log.txt");
#endif
using namespace std;

vector<int> G[501];
vector<int> Links[501];
set<int> Q;
set<int>::iterator itQ;
unordered_map<int, unordered_map<int,vector<int> > > F;
unordered_map<int, unordered_map<int,vector<int> > >::iterator itF;
int n,m,t,k,u,v,a,b,c;

set<int> TS,TU;
set<int>::iterator itTS,itTU;
unordered_map<int, vector<int> > tmpSearch;
unordered_map<int, vector<int> >::iterator itTmpS;
unordered_map<int, unordered_map<int, int> > tmpUpdate;
unordered_map<int, unordered_map<int, int> > ::iterator itTmpU;

void enque(const int& time,const int& point){
	#ifdef DEBUG
		if(Links[point].size()>500) return; 
	#endif
	unordered_map<int, unordered_map<int,vector<int> > >::iterator it = F.find(time);
	if(it == F.end()){
		Q.insert(time);
		unordered_map<int,vector<int> > M;
		M.insert(pair<int,vector<int> >(point,vector<int>(Links[point])));
		F.insert(pair<int,unordered_map<int,vector<int> > >(time,M));
	}
	else{
		unordered_map<int, vector<int> >::iterator itM = it->second.find(point);
		if (itM == it->second.end()) {
			it->second.insert(pair<int, vector<int> >(point, vector<int>(Links[point])));
		}
		else {
			const vector<int>& vM = itM->second;
			int n1 = Links[point].size(), n2 = vM.size();
			if (n1 > n2 || n1 == n2&&Links[point].back() < vM.back()) {
				itM->second = vector<int>(Links[point]);
			}
		}
	}
}

void receiveChain() {
	int timeQ = Q.empty() ? ::b : 0, timeT, flagQ=0, b = TS.empty()? ::b : *TS.begin();
	do {
		while(!TU.empty()&& (timeT = *(itTU = TU.begin())) < timeQ){
			const unordered_map<int,int>& M = tmpUpdate.find(timeT)->second;
			for (unordered_map<int,int>::const_iterator itM = M.begin(); itM != M.end(); ++itM){
				Links[itM->first].emplace_back(itM->second);
				enque(timeT + t, itM->first);
			}
			TU.erase(itTU);
			tmpUpdate.erase(timeT);
		}
		if (flagQ == 1) {
			const unordered_map<int,vector<int> >& M = F.find(timeQ)->second;
			for (unordered_map<int,vector<int> >::const_iterator itM = M.begin(); itM != M.end(); ++itM) {
				const int& v = itM->first;
				const vector<int>& link = itM->second;
				for (int i = 0, ni = G[v].size(), n1, n2; i<ni; ++i) {
					n1 = link.size(), n2 = Links[G[v][i]].size();
					if (n1<n2 || n1 == n2&&link.back() >= Links[G[v][i]].back()) continue;

					Links[G[v][i]] = link;
					enque(t + timeQ, G[v][i]);
				}
			}
			F.erase(timeQ);
			Q.erase(itQ);
			continue;
		}
		flagQ = 1;
	} while (!Q.empty() && (timeQ = *(itQ = Q.begin())) <= b);
}

void outputChain() {
	for (itTS = TS.begin(); itTS != TS.end();++itTS) {
		itTmpS = tmpSearch.find(*itTS);
		const vector<int>& V = itTmpS->second;
		itTmpU = tmpUpdate.find(itTmpS->first);
		for (int i = 0, ni = V.size(), link_length, link_value, link_flag; i<ni; ++i) {
			link_length = Links[V[i]].size();
			link_flag = 0;
			if (itTmpU != tmpUpdate.end()) {
				const unordered_map<int, int>& M = itTmpU->second;
				unordered_map<int, int>::const_iterator itM = M.find(V[i]);
				if (itM != M.end()) {
					++link_length;
					link_flag = 1;
					link_value = itM->second;
				}
			}
			#ifdef DEBUG
				LOG << link_length;
			#endif
			for (int j = 0, nj = Links[V[i]].size(); j<nj; ++j) {
			#ifdef DEBUG
				LOG << ' ' << Links[V[i]][j];
			#endif
			}
			if (link_flag == 1) {
			#ifdef DEBUG
				LOG << ' ' << link_value;
			#endif
			}
			#ifdef DEBUG
				LOG << endl;
			#endif
		}
	}
	tmpSearch.clear();
	TS.clear();
}

void updateChain() {
	for(itTmpU=tmpUpdate.begin();itTmpU!=tmpUpdate.end();++itTmpU){
		const unordered_map<int,int>& M = itTmpU->second;
		const int & timeU = itTmpU->first;
		for (unordered_map<int, int>::const_iterator itM = M.begin(); itM != M.end(); ++itM) {
			Links[itM->first].emplace_back(itM->second);
			enque(timeU + t, itM->first);
		}
	}
	tmpUpdate.clear();
	TU.clear();
}

void solve(){
	receiveChain();
	outputChain();
	updateChain();
}

int main(){
	#ifdef DEBUG
		ifstream cin("input.txt");
		clock_t c1 = clock();
	#endif
	ios_base::sync_with_stdio(false);
	cin.tie(NULL);
	cin>>n>>m;
	for(int i=0;i<m;++i){
		cin>>u>>v;
		G[u].emplace_back(v);
		G[v].emplace_back(u);
	}
	for (int i = n; i > 0; --i) {
		Links[i].emplace_back(0);
	}

	cin>>t>>k;
	string s;
	for(int i=0,j,nj,lastTaskId=1,xk=k-1;i<k;++i){
		cin>>a>>b,c=-1;
		getline(cin,s);
		j=0,nj = s.size();
		while(j<nj&&s[j]==' ') ++j;
		bool isNegative = j<nj&&s[j]=='-'&&++j>0;
		if(j<nj&&isdigit(s[j])){
			c=0;
			while(j<nj&&isdigit(s[j])){
				c=c*10+(s[j]-'0');
				++j;
			}
			if(isNegative) c=-c;
		}

		if(b!=lastTaskId){
			solve();
		}
		
		if(c==-1){
			if ((itTmpS = tmpSearch.find(b)) == tmpSearch.end()) {
				vector<int> v(1,a);
				tmpSearch.insert(pair<int, vector<int> >(b,v));
				TS.insert(b);
			}
			else {
				itTmpS->second.emplace_back(a);
			}
		}
		else{
			if((itTmpU=tmpUpdate.find(b))==tmpUpdate.end()){
				unordered_map<int,int> M;
				M.insert(pair<int,int>(a,c));
				tmpUpdate.insert(pair<int,unordered_map<int,int> >(b,M));
				TU.insert(b);
			}
			else{
				itTmpU->second.insert(pair<int,int>(a,c));
			}
		}
		
		if(i==xk&&!tmpSearch.empty()){
			solve();
		}
		lastTaskId=b;
	}

	#ifdef DEBUG
		clock_t c2 = clock();
		cout << endl << c2 - c1 << "ms" << endl;
	#endif
	return 0;
}
#include<iostream>
#include<cstdlib>
#include<fstream> 
#include<set>
using namespace std;

int main(){
	int n = 500,m = 10000,t=rand()%1000+1,k=30000;
	ofstream fout("input.txt");
	set<pair<int,int> > S;
	
	fout<<n<<" "<<m<<endl;
	while(S.size()<m){
		int u = rand()%500 + 1,v = rand()%500 +1;
		pair<int,int> p;
		if(u<v){
			p = pair<int,int>(u,v);
		}
		else{
			p = pair<int,int>(v,u);
		}
		if(S.find(p)==S.end()){
			fout<<p.first<<" "<<p.second<<endl;
				S.insert(p);
		}
	}
	
	fout<<t<<" "<<k<<endl;
	for(int i=0,a,b = 1,c;i<k;++i){
		a = rand()%500 + 1;
		if((rand()%100)>60){
			if((rand()%100)>80){
				b = b +(rand()%t) + (t*rand())%3;
			}
			else{
				b = b +rand()%t;
			}
		}
		c = 1*rand()*rand()*rand();
		if((rand()%100)>30){
			fout<<a<<" "<<b<<endl;
		}
		else{
			fout<<a<<" "<<b<<" "<<c<<endl;
		}
	}
	
	return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值