[2的n次方]
高精度乘法複習資料:https://www.cnblogs.com/jayxuan/p/18287673
重複做以下操作 $n $ 次:對每一位乘以 $2 $,然後進位。(當然也可以使用正常的高精度乘法) 【參考程式碼】 #include<bits/stdc++.h> using namespace std; int ans[59]; int main() { int n; cin >> n; ans[0] = 1; for (int i = 0; i < n; i++) { for (int j = 0; j < 50; j++) { ans[j] *= 2; } for (int j = 0; j < 50; j++) { ans[j + 1] += ans[j] / 10; ans[j] %= 10; } } int len = 49; while (!ans[len]) len--; for (int i = len; i >= 0; i--) cout << ans[i]; return 0; }
[最小函式值]
#include<bits/stdc++.h> using namespace std; int main() { int n, m; // n 表示函式個數,m 表示每個函式考慮的 x 的範圍(1 到 m) cin >> n >> m; priority_queue<int> q; // 使用最大堆(預設)來儲存當前遇到的最小值 for (int i = 0; i < n; i++) { // 遍歷每個函式 int a, b, c; // 函式 ax^2 + bx + c 的係數 cin >> a >> b >> c; for (int j = 1; j <= m; j++) { // 遍歷 x 的取值範圍(1 到 m) int tem = a * j * j + b * j + c; // 計算當前 x 值下的函式結果 if (q.size() < m) q.push(tem); // 如果堆中元素少於 m 個,直接加入 else if (q.top() > tem) { // 如果堆頂元素(即當前最大元素)大於當前計算值 q.pop(); // 彈出堆頂元素 q.push(tem); // 加入當前計算值 } else break; // 如果當前計算值不小於堆頂元素,則無需繼續計算,因為後續值會更大 } } vector<int> ve; // 用於儲存所有函式的前 m 小值 while (q.size()) { // 當堆不為空時 ve.push_back(q.top()); // 將堆頂元素(當前最大值,即所有值中的最小之一)加入向量 q.pop(); // 彈出堆頂元素 } // 由於我們需要從大到小輸出,而 vector 預設從小到大儲存,所以逆序遍歷 for (int i = ve.size() - 1; i >= 0; i--) cout << ve[i] << " "; return 0; }
[獎金]
拓撲排序複習:https://www.cnblogs.com/jayxuan/p/18238671
這段程式碼實現了一個基於圖論的問題,通常被稱為“獎金分配”或“拓撲排序中的最長路徑”問題。在這個問題中,你有一個有向無環圖(DAG),圖中的每個節點代表一個員工,每條有向邊從員工A指向員工B表示A是B的直接上級。公司決定根據員工的層級(即從CEO到每個員工的最長路徑長度)來分配獎金,CEO的層級為1,並且每個員工的獎金是其層級的100倍。如果圖中存在環,則無法確定層級,輸出"Poor Xed"。 #include<bits/stdc++.h> using namespace std; const int maxn = 1e4 + 9; // 定義最大節點數 vector<int> ve[maxn]; // 鄰接表,儲存每個節點的直接下級列表 int deg[maxn]; // 儲存每個節點的入度(即有多少節點指向它) int ans[maxn]; // 儲存每個節點的層級(獎金的倍數) int main() { int n, m; // n是節點數(員工數),m是邊數(關係數) cin >> n >> m; // 讀取邊資訊,構建鄰接表和入度陣列 for (int i = 0; i < m; i++) { int a, b; cin >> a >> b; ve[b].push_back(a); // b是a的上級,所以a是b的下級 deg[a]++; // a的入度加1 } queue<int> q; // 使用佇列進行拓撲排序 // 將所有入度為0的節點(即沒有上級的節點,可能是CEO)加入佇列,並初始化其層級為1(獎金為100) for (int i = 1; i <= n; i++) { if (deg[i] == 0) q.push(i), ans[i] = 100; } // 拓撲排序過程 while (q.size()) { int r = q.front(); // 取出佇列中的節點 q.pop(); // 遍歷該節點的所有下級 for (int i = 0; i < ve[r].size(); i++) { int y = ve[r][i]; // 更新下級的層級為當前節點層級加1(獎金倍數增加) ans[y] = max(ans[y], ans[r] + 1); // 下級的入度減1 if (--deg[y] == 0) q.push(y); // 如果下級入度變為0,則加入佇列繼續處理 } } // 檢查是否所有節點都被處理(即圖中是否存在環) for (int i = 1; i <= n; i++) { if (deg[i]) { // 如果有節點的入度不為0,說明存在環 cout << "Poor Xed"; // 輸出"Poor Xed"並結束程式 return 0; } } int sum = 0; // 計算所有員工的總獎金 for (int i = 1; i <= n; i++) sum += ans[i]; // 這裡實際上計算的是獎金的倍數之和,如果需要真實獎金,應乘以100 // 注意:如果題目要求輸出的是獎金總額(即倍數乘以100),則應將sum乘以100後輸出 cout << sum; // 輸出獎金的倍數之和(如果需要,可以乘以100後輸出) return 0; }
[最短網路]
最小生成樹複習:https://www.cnblogs.com/jayxuan/p/18263315
【演算法分析】 題目是要求“能連線所有農場並所用光纖最短的方案”,這其實就是最小生成樹。將所有邊提取出來,存到陣列裡(重複的邊可以不儲存),然後跑最小生成樹即可。 【參考程式碼】 #include<bits/stdc++.h> using namespace std; struct node { int x, y, w; }; vector<node> ve; bool cmp(node A, node B) { return A.w < B.w; } int fa[109]; int get(int x) { if (fa[x] == x) return x; return fa[x] = get(fa[x]); } void merge(int x, int y) { fa[get(x)] = get(y); } int main() { int n; cin >> n; for (int i = 1; i <= n; i++) fa[i] = i; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { int a; cin >> a; if (j > i) ve.push_back({ i,j,a }); } } sort(ve.begin(), ve.end(), cmp); int ans = 0; for (int i = 0; i < ve.size(); i++) { if (get(ve[i].x) == get(ve[i].y)) continue; ans += ve[i].w; merge(ve[i].x, ve[i].y); } cout << ans; return 0; }
12課-階段測評練習課
選擇題1
選擇題2:構建大根堆複習
選擇題3:並查集知識複習
選擇題4:哈夫曼樹 :https://www.cnblogs.com/jayxuan/p/18176107
組合題目
最小生成樹複習連結:https://www.cnblogs.com/jayxuan/p/18263315
這是一份C++ prim的程式碼,小碼君不小心打翻了墨水,有幾處需要你來補齊
#include<bits/stdc++.h>
using namespace std;
int n,m;
struct node{
int to,tot;
};
int dis[200005];
bool vis[200005];
vector<node>g[200005];
int sum=0;
void prim(){
memset(vis,false,sizeof vis);
memset(dis,666666,sizeof dis);
【________1________】
for(int i=1;i<=n;i++){
int x,zx=INT_MAX-1;
for(int j=1;j<=n;j++){
if(【________2________】&&dis[j]<zx){
zx=dis[j];
x=j;
}
}
【________3________】
for(int j=0;【________4________】;j++){
int v=g[x][j].to;
int tot=g[x][j].tot;
if(!vis[v]&&dis[v]>tot){
dis[v]=tot;
}
}
【________5________】
}
return ;
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++){
int x,y,z;
cin>>x>>y>>z;
g[x].push_back({y,z});
g[y].push_back({x,z});
}
prim();
cout<<sum<<endl;
return 0;
}
1.
(一)
-
A.
A、dis[1]=0;
-
B.
B、dis[1]=1;
-
C.
C、vis[1]=0;
-
D.
D、vis[1]=1;
2.
(二)
-
A.
A、!vis[i]
-
B.
B、!vis[j]
-
C.
C、vis[i]
-
D.
D、vis[j]
3.
(三)
-
A.
A、dis[x]=1;
-
B.
B、dis[x]=0;
-
C.
C、vis[x]=false;
-
D.
D、vis[x]=true;
4.
(四)
-
A.
A、j<g[x].size()
-
B.
B、j<n
-
C.
C、j<m
-
D.
D、j<=n
5.
(五)
-
A.
A、sum=max(dis[x],sum);
-
B.
B、sum=min(dis[x],sum);
-
C.
C、sum+=dis[x];
-
D.
D、sum+=vis[x];
-
【演算法分析】 高精度模擬即可 【參考程式碼】 #include<bits/stdc++.h> using namespace std; int a[40000],h; //記錄最高位,節省時間 void f(int n){ //函式遞迴 if(n==1){a[0]=1;return;} f(n-1); int x=0; for(int i=0;i<=h+4;i++){ //利用x記錄進位,一次迴圈搞定 a[i]*=n; //n小,直接乘 a[i]+=x; x=a[i]/10; a[i]%=10; } h+=4; while(!a[h])h--; } int main(){ int n; cin>>n; f(n); for(int i=h;i>=0;i--)cout<<a[i]; return 0; }
[無線通訊網] 題目描述 國防部計劃用無線網路連線若干個邊防哨所。2 種不同的通訊技術用來搭建無線網路; 每個邊防哨所都要配備無線電收發器;有一些哨所還可以增配衛星電話。 任意兩個配備了一條衛星電話線路的哨所(兩邊都ᤕ有衛星電話)均可以通話,無論他們相距多遠。而只透過無線電收發器通話的哨所之間的距離不能超過 D,這是受收發器的功率限制。收發器的功率越高,通話距離 D 會更遠,但同時價格也會更貴。 收發器需要統一購買和安裝,所以全部哨所只能選擇安裝一種型號的收發器。換句話說,每一對哨所之間的通話距離都是同一個 D。你的任務是確定收發器必須的最小通話距離 D,使得每一對哨所之間至少有一條通話路徑(直接的或者間接的)。 提示 對於 100% 的資料保證:1≤S≤100,S<P≤500,0≤x,y≤10000。 輸入格式 輸入資料第 1 行,2 個整數 S 和 P,S 表示可安裝的衛星電話的哨所數,P 表示邊防哨所的數量。接下里 P 行,每行兩個整數 x,y 描述一個哨所的平面座標 (x,y),以 km 為單位。 輸出格式 第 1 行,1 個實數 D,表示無線電收發器的最小傳輸距離,精確到小數點後兩位。 樣例組 輸入#1 輸出#1 2 4 0 100 0 300 0 600 150 750 212.13
#include<bits/stdc++.h> using namespace std; // 節點數n和邊數m int n,m; // 並查集陣列,用於快速查詢和合並集合 int arr[100005]; // 邊的結構體,包含兩個端點和邊的權重(距離) struct node{ double x; // 邊的起點 double y; // 邊的終點 double z; // 邊的權重(兩點間的距離) }; // 儲存所有邊的陣列 node a[2005]; // 路徑(但這裡命名不準確,應為邊) node lss[500005]; // 儲存所有計算得到的邊和它們的權重(距離),lss可能代表line segment或者length sorted segments // 比較函式,用於對邊按權重進行排序 bool cmp(node x,node y){ return x.z<y.z; } // 查詢函式,用於並查集,返回元素所在集合的根 int find(int x){ if(x==arr[x])return x; return arr[x]=find(arr[x]); // 路徑壓縮最佳化 } // 合併函式,將兩個元素所在的集合合併 void hb(int x,int y){ int xx=find(x); int yy=find(y); if(xx!=yy) arr[xx]=yy; // 只在兩個元素不在同一集合時合併 } int main(){ cin>>n>>m; // 輸入節點數和邊數 for(int i=1;i<=m;i++){ arr[i]=i; // 初始化並查集,每個元素自己是一個集合 } for(int i=1;i<=m;i++){ cin>>a[i].x>>a[i].y; // 輸入每條邊的兩個端點 a[i].z = 0; // 這裡a[i].z沒有直接賦值,但在實際使用中應該透過計算得到,但在這個程式碼片段中它沒有被使用 } int t=0; // 用於記錄lss陣列中邊的數量 for(int i=1;i<=m;i++){ for(int j=1;j<i;j++){ t++; lss[t].x=i; lss[t].y=j; lss[t].z=sqrt((a[i].x-a[j].x)*(a[i].x-a[j].x)+(a[i].y-a[j].y)*(a[i].y-a[j].y)); // 計算兩點間的歐幾里得距離 } } int w=0; // 記錄已加入MST的邊數 sort(lss+1,lss+1+t,cmp); // 按邊的權重對lss陣列進行排序 for(int i=1;i<=t;i++){ if(find(lss[i].x)!=find(lss[i].y)){ // 如果當前邊的兩個端點不在同一集合中 hb(lss[i].x,lss[i].y); // 合併這兩個集合 w++; // 增加已加入MST的邊數 if(w==m-n+1){ // 當加入的邊數等於節點數減一時,MST構建完成 printf("%.2f",lss[i].z); // 輸出最後一條加入MST的邊的權重(即MST的總權重) return 0; } } } // 如果無法構建MST(例如,圖中存在多個連通分量且節點數小於n),則這裡會返回,但題目沒有給出明確的處理 return 0; }
[小碼君的賬單] 題目描述 小碼君在一次聚會中,不慎遺失了自己的錢包,在接下來的日子,面對小碼君的將是一系列的補卡手續和堆積的賬單… 在小碼君的百般懇求下,老闆最終同意延緩賬單的支付時間。可老闆又提出,必須從目前還沒有支付的所有賬單中選出面額最大和最小的兩張,並把他們付清。還沒有支付的賬單會被保留到下一天。 請你幫他計算出支付的順序。 輸入格式 第1行:一個正整數N(N≤100),表示小碼君補辦銀聯卡總共的天數。 第2行到第N+1 行:每一行描述一天中收到的帳單。先是一個非負整數M≤100,表示當天收到的賬單數,後跟M個正整數(都小於1000000),表示每張帳單的面額。 輸入資料保證每天都可以支付兩張帳單。 輸出格式 輸出共N 行,每行兩個用空格分隔的整數,分別表示當天支付的面額最小和最大的支票的面額。 樣例組 輸入#1 輸出#1 4 3 3 6 5 2 8 2 3 7 1 7 0 3 6 2 8 1 7 5 7
【演算法分析】 設大頂堆與小頂堆,裡面儲存的資料型別為賬單型別。大頂堆中賬單面額更大的更優先,小頂堆中賬單面額更小的更優先。 然後每天從大小根堆的頂部取出一個 【參考程式碼】 #include<bits/stdc++.h> using namespace std; int n,m,cnt,a[1500010],v[1500010]; pair<int,int>v1,v2; priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q1; priority_queue<pair<int,int> >q2; int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&m); for(int j=cnt+1;j<=cnt+m;j++){ scanf("%d",&a[j]); q1.push(make_pair(a[j],j)); q2.push(make_pair(a[j],j)); } while(v[q1.top().second])q1.pop(); v1=q1.top(); printf("%d ",v1.first); v[v1.second]=1; while(v[q2.top().second])q2.pop(); v2=q2.top(); printf("%d\n",v2.first); v[v2.second]=1; cnt+=m; } }