1. 程式人生 > 其它 >CSP201912-4 區塊鏈

CSP201912-4 區塊鏈

CSP201912-4 區塊鏈

題目

題目可以在CSP官網中檢視到喲!

結果

執行結果

演算法分析

這道題目竟然也是一個模擬題,模擬的思想也不是很複雜。這道題首先要注意的就是節點更新主鏈的條件(有兩個,題目已經很清楚地說明了),其次要注意的就是隻有節點的主鏈更新了,其才會將自己的主鏈向周圍節點發送,而且傳送的過程是需要的時間。剩下的就是純粹的模擬了,具體程式碼詳解如下。

程式碼詳解

1、全域性變數

在小編的程式碼中含有四個 int 型別的變數,分別為:n(代表n個節點),m(代表m條邊),t(代表傳送所需時間),k(代表操作的數量);還含有兩個 vector<vector< int >>型別的陣列:graph(代表雙向圖),ans(儲存每一個節點的主鏈);最後含有一個map<int, unordered_map<int, array<vector< int >, 2>>>型別的op(輔助記錄某時刻、某一結點的情況)。具體如下:

int n, m, t, k;
vector<vector<int>> graph(505);
vector<vector<int>> ans(505, { 0 });
map<int, unordered_map<int, array<vector<int>, 2>>> op;

2、主函式

在主函式裡面,首先要做的就是讀取輸入資訊,根據輸入資訊建圖,小編是利用vector<>陣列建圖的。接下來,讀取k個操作,根據不同的操作種類進行不一樣的操作:(1)操作含有兩個數,這個呼叫query()函式查詢第a個節點在時刻b時的主鏈;(2)操作含有三個數,這個直接按照節點數、時刻、新塊訊號進行更新即可。具體程式碼如下:

int main()
{
	freopen("in.in", "r", stdin);
	freopen("out.out", "w", stdout);
	int i, j;
	//n個節點,m條邊
	cin >> n >> m;
	//建圖
	for (i = 1; i <= m; i++)
	{
		int u, v;
		cin >> u >> v;
		graph[u].push_back(v);
		graph[v].push_back(u);
	}
	//傳送時間t,k個操作
cin >> t >> k; while (k--) { int a, b, c; cin >> a >> b; //查詢 if (cin.get() == '\n' || cin.eof()) { query(b); cout << ans[a].size(); for (i = 0; i < ans[a].size(); i++) cout << " " << ans[a][i]; cout << endl; } //更新新塊 else { cin >> c; op[b][a][1].push_back(c); } } return 0; }

3、查詢函式query()

遍歷op中的每一項元素,由於輸入的特殊性,op中首個int型別的鍵值是按照由小到大的順序的,如果當前元素的首個int型別的鍵值大於查詢的時刻,則停止遍歷;否則繼續如下過程:遍歷該時刻的每一個更新的節點,如果有接收到能使自身更新的話,則先進行自身的主鏈更新;接下來,如果含有新塊的更新,則在主鏈後面直接進行更新。如上操作做完之後,如果節點有更新,則將 t 時刻後的變動更新到op中。最後將該查詢時刻之前的在 op 中的項刪除,具體程式碼如下:

void query(int time)
{
	for (auto operation_d : op)
	{
		int operation_time = operation_d.first;
		if (operation_time > time) break;
		for (auto element : operation_d.second)
		{
			int node = element.first;
			auto& in = element.second[0];
			auto& out = element.second[1];
			int flag = 0;
			if (check(ans[node], in))
			{
				flag = 1;
				ans[node] = in;
			}
			for (int b : out)
				ans[node].push_back(b);
			if (flag || !out.empty())
				update(operation_time + t, node);
		}
	}
	op.erase(op.begin(), op.upper_bound(time));
}

4、檢查函式check()

該函式的目的就是判斷是否達到更新條件,題目中提到的兩個更新條件達到其中一個即可進行更新(也就是返回1),具體程式碼如下:

int check(vector<int> a, vector<int>b)
{
	if (a.size() < b.size() || (a.size() == b.size() && a.back() > b.back())) return 1;
	return 0;
}

5、更新函式update()

當有節點更新會將其更新後的主鏈經過時間t後傳送到相鄰節點中,而這個函式就是對時間t後的情況進行更新。具體程式碼如下:

void update(int time, int node)
{
	auto &message = ans[node];
	for (auto it : graph[node])
	{
		auto &tmp = op[time][it][0];
		if ((tmp.empty() && check(ans[it], message)) || (!tmp.empty() && check(tmp, message)))
			tmp = message;
	}
}

完整滿分程式碼

#include<cstdio>
#include<iostream>
#include<vector>
#include<unordered_map>
#include<map>
#include<array>
using namespace std;
int n, m, t, k;
vector<vector<int>> graph(505);
vector<vector<int>> ans(505, { 0 });
map<int, unordered_map<int, array<vector<int>, 2>>> op;
int check(vector<int> a, vector<int>b)
{
	if (a.size() < b.size() || (a.size() == b.size() && a.back() > b.back())) return 1;
	return 0;
}
void update(int time, int node)
{
	auto &message = ans[node];
	for (auto it : graph[node])
	{
		auto &tmp = op[time][it][0];
		if ((tmp.empty() && check(ans[it], message)) || (!tmp.empty() && check(tmp, message)))
			tmp = message;
	}
}
void query(int time)
{
	for (auto operation_d : op)
	{
		int operation_time = operation_d.first;
		if (operation_time > time) break;
		for (auto element : operation_d.second)
		{
			int node = element.first;
			auto& in = element.second[0];
			auto& out = element.second[1];
			int flag = 0;
			if (check(ans[node], in))
			{
				flag = 1;
				ans[node] = in;
			}
			for (int b : out)
				ans[node].push_back(b);
			if (flag || !out.empty())
				update(operation_time + t, node);
		}
	}
	op.erase(op.begin(), op.upper_bound(time));
}
int main()
{
	int i, j;
	//n個節點,m條邊
	cin >> n >> m;
	//建圖
	for (i = 1; i <= m; i++)
	{
		int u, v;
		cin >> u >> v;
		graph[u].push_back(v);
		graph[v].push_back(u);
	}
	//傳送時間t,k個操作
	cin >> t >> k;
	while (k--)
	{
		int a, b, c;
		cin >> a >> b;
		//查詢
		if (cin.get() == '\n' || cin.eof())
		{
			query(b);
			cout << ans[a].size();
			for (i = 0; i < ans[a].size(); i++)
				cout << " " << ans[a][i];
			cout << endl;
		}
		//更新新塊
		else
		{
			cin >> c;
			op[b][a][1].push_back(c);
		}
	}
	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

輸出

2 0 1
2 0 2
2 0 3
2 0 4
2 0 5
2 0 1
2 0 1
2 0 1
2 0 1
2 0 1
3 0 1 10
4 0 1 10 9
3 0 1 10
3 0 1 10
3 0 1 10
4 0 1 10 9
4 0 1 10 9
4 0 1 10 9
4 0 1 10 9
4 0 1 10 9