U7-11課綜合練習+12課階段測評練習——複習練習題目

小虾同学發表於2024-07-12

[2的n次方]

高精度乘法複習資料:https://www.cnblogs.com/jayxuan/p/18287673

U7-11課綜合練習+12課階段測評練習——複習練習題目
重複做以下操作 $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;
}
View Code

[最小函式值]

U7-11課綜合練習+12課階段測評練習——複習練習題目
#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;  
}
View Code

[獎金]

拓撲排序複習:https://www.cnblogs.com/jayxuan/p/18238671

U7-11課綜合練習+12課階段測評練習——複習練習題目
這段程式碼實現了一個基於圖論的問題,通常被稱為“獎金分配”或“拓撲排序中的最長路徑”問題。在這個問題中,你有一個有向無環圖(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;  
}
View Code

[最短網路]

最小生成樹複習:https://www.cnblogs.com/jayxuan/p/18263315

U7-11課綜合練習+12課階段測評練習——複習練習題目
【演算法分析】
題目是要求“能連線所有農場並所用光纖最短的方案”,這其實就是最小生成樹。將所有邊提取出來,存到陣列裡(重複的邊可以不儲存),然後跑最小生成樹即可。

【參考程式碼】
#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;
}
View Code

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];

U7-11課綜合練習+12課階段測評練習——複習練習題目
【演算法分析】
高精度模擬即可

【參考程式碼】
#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;
}
View Code

[無線通訊網]
題目描述
國防部計劃用無線網路連線若干個邊防哨所。2 種不同的通訊技術用來搭建無線網路;


每個邊防哨所都要配備無線電收發器;有一些哨所還可以增配衛星電話。


任意兩個配備了一條衛星電話線路的哨所(兩邊都ᤕ有衛星電話)均可以通話,無論他們相距多遠。而只透過無線電收發器通話的哨所之間的距離不能超過 D,這是受收發器的功率限制。收發器的功率越高,通話距離 D 會更遠,但同時價格也會更貴。


收發器需要統一購買和安裝,所以全部哨所只能選擇安裝一種型號的收發器。換句話說,每一對哨所之間的通話距離都是同一個 D。你的任務是確定收發器必須的最小通話距離 D,使得每一對哨所之間至少有一條通話路徑(直接的或者間接的)。


提示
對於 100% 的資料保證:1≤S≤100,S<P≤5000≤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
U7-11課綜合練習+12課階段測評練習——複習練習題目
#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;  
}
View Code

[小碼君的賬單]
題目描述
小碼君在一次聚會中,不慎遺失了自己的錢包,在接下來的日子,面對小碼君的將是一系列的補卡手續和堆積的賬單… 在小碼君的百般懇求下,老闆最終同意延緩賬單的支付時間。可老闆又提出,必須從目前還沒有支付的所有賬單中選出面額最大和最小的兩張,並把他們付清。還沒有支付的賬單會被保留到下一天。 請你幫他計算出支付的順序。


輸入格式
第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

U7-11課綜合練習+12課階段測評練習——複習練習題目
【演算法分析】
設大頂堆與小頂堆,裡面儲存的資料型別為賬單型別。大頂堆中賬單面額更大的更優先,小頂堆中賬單面額更小的更優先。

然後每天從大小根堆的頂部取出一個

【參考程式碼】
#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;
    }
}
View Code