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