2022暑假每日一题笔记(三)

T1--693. 行程排序

玛丽需要从某地飞往另一目的地,由于没有直达飞机,所以需要在中途转很多航班。
例如:SFO -> DFW DFW -> JFK JFK -> MIA MIA -> ORD。
显然旅途中不可能到同一中转城市两次或以上,因为这没有意义。
不幸的是,她将自己的机票的顺序搞乱了,将机票按乘坐顺序整理好对她来说不是一件容易的事。
请你帮助玛丽整理机票,使机票按正确顺序排列。

输入格式
第一行包含整数 T,表示共有 T 组测试数据。
每组数据第一行包含整数 N。
接下来 2N 行,每 2 行一组,表示一张机票的信息,每行包含一个字符串,其中第一行表示出发地,第二行表示目的地。

输出格式
每组数据输出一个结果,每个结果占一行。
结果表示为 Case #x: y,其中 x 是组别编号(从 1 开始),y 是表示实际行程的机票列表,行程中的每个航段应以 source-destination 的形式输出,航段之间用空格隔开。

数据范围
1≤T≤100,
1≤N≤10000
输入样例:
2
1
SFO
DFW
4
MIA
ORD
DFW
JFK
SFO
DFW
JFK
MIA
输出样例:
Case #1: SFO-DFW
Case #2: SFO-DFW DFW-JFK JFK-MIA MIA-ORD

参考了y总的代码。

#include <bits/stdc++.h>
using namespace std;
int n;

int main(){
    int t;
    cin >> t;
    for (int x = 1;x <= t;x ++){
        unordered_map<string,int> s;
        unordered_map<string,string> link;
        
        cin >> n;string a,b;
        for (int i = 0;i < n;i ++){
            cin >> a >> b;
            s[a] ++,s[b] ++; // 统计机场出现次数
            link.insert({a,b}); // 记录机票
        }
        
        string head; // 遍历查找起点
        // 起点必然满足两个条件:1.只在一张机票出现 2.不能作为目的地
        for (auto &[k,v] : s){
            if (v == 1 && link.count(k)) head = k;
        }
        
        string str = head;
        printf("Case #%d: ",x);
        for (int i = 0;i < n;i ++){
            cout << str << "-";
            str = link[str];
            cout << str << ' ';
        }
        puts("");
    }
    return 0;
}

T2--3428. 放苹果

把 M 个同样的苹果放在 N 个同样的盘子里,允许有的盘子空着不放,问共有多少种不同的分法?
盘子相对顺序不同,例如 511151 算作同一种分法。

输入格式
输入包含多组测试数据。
每组数据占一行,包含两个整数 M 和 N。

输出格式
每组数据,输出一行一个结果表示分法数量。

数据范围
1≤M,N≤10
输入样例:
7 3
输出样例:
8

不会,参考题解
DFS思路类似递归实现组合型枚举。
对于1,1,5和1,5,1两种放法,本题中将它们视为一种方案,所以DFS搜索时通过升序加以限制,只记录升序的方案,这样就不会重复计算。

#include <bits/stdc++.h>
using namespace std;
int m,n;

int dfs(int u,int last,int sum){
    // u:放置第u个盘子,last:上个盘子放的苹果数,sum:剩余可放苹果数
    if (u == n+1){
        if (sum == 0) return 1; // 全部苹果放入n个盘子为一个方案
        return 0;
    }
    
    int res = 0;// 放完前u个盘子,枚举后面的盘子
    for (int i = last;i <= sum;i ++){
        // 从上次放的苹果数开始枚举,保证方案不重复
        res += dfs(u+1,i,sum - i);
    }
    return res;
}

int main(){
    while (cin >> m >> n){
        cout << dfs(1,0,m) << '\n';
    }
    return 0;
}

T3--3477. 简单排序

给定一个包含 n 个整数的数组,请你删除数组中的重复元素并将数组从小到大排序后输出。

输入格式
第一行包含一个整数 n。
第二行包含 n 个不超过 1000 的正整数。

输出格式
输出去重和排序完毕后的数组。

数据范围
1≤n≤1000
输入样例:
6
8 8 7 3 7 7
输出样例:
3 7 8

在离散化中用到的数组排序和去重。

#include <bits/stdc++.h>
using namespace std;

int main(){
    int n,x;
    vector<int> v;
    cin >> n;
    for (int i = 0;i < n;i ++){
        cin >> x;
        v.push_back(x);
    }
    
    sort(v.begin(),v.end());
    v.erase(unique(v.begin(),v.end()),v.end());
    for (auto it : v) cout << it << ' ';
    return 0;
}

更加简单的做法:

#include<bits/stdc++.h>
using namespace std;

int main()
{
    int n,i,a[1001];
    cin>>n;
    for(i=1;i<=n;i++)cin>>a[i];
    sort(a+1,a+1+n);
    for(i=1;i<=n;i++)if(a[i]!=a[i-1])cout<<a[i]<<' ';
    return 0;
}

T4--3531. 哈夫曼树

给定 N 个权值作为 N 个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树(Huffman Tree)。
现在,给定 N 个叶子结点的信息,请你构造哈夫曼树,并输出该树的带权路径长度。

相关知识:
1、路径和路径长度
在一棵树中,从一个结点往下可以达到的孩子或孙子结点之间的通路,称为路径。通路中分支的数目称为路径长度。若规定根结点的层数为 1,则从根结点到第 L 层结点的路径长度为 L−12、结点的权及带权路径长度
若将树中结点赋给一个有着某种含义的数值,则这个数值称为该结点的权。结点的带权路径长度为:从根结点到该结点之间的路径长度与该结点的权的乘积。
3、树的带权路径长度
树的带权路径长度规定为所有叶子结点的带权路径长度之和,记为 WPL。

输入格式
第一行包含整数 N,表示叶子结点数量。
第二行包含 N 个整数,表示每个叶子结点的权值。

输出格式
输出一个整数,表示生成哈夫曼树的带权路径长度。

数据范围
2≤N≤1000,
叶子结点的权值范围 [1,100]。

输入样例:
5
1 2 2 5 9
输出样例:
37
#include <bits/stdc++.h>
using namespace std;

int main(){
    int n;
    cin >> n;
    
    int x;
    priority_queue<int,vector<int>,greater<int>> heap;
    for (int i = 0;i < n;i ++) {
        cin >> x;
        heap.push(x);
    }
    
    int res = 0;
    for (int i = 0;i < n-1;i ++){
        int a = heap.top();heap.pop();
        int b = heap.top();heap.pop();
        int s = a + b;
        heap.push(s);
        res += s;
    }
    cout << res << '\n';
    return 0;
}

T5--3438. 数制转换

求任意两个不同进制非负整数的转换(2 进制 ∼ 16 进制),所给整数在 int 范围内。
不同进制的表示符号为(01,…,9,a,b,…,f)或者(01,…,9,A,B,…,F)

输入格式
输入只有一行,包含三个整数 a,n,b。a 表示其后的 n 是 a 进制整数,b 表示欲将 a 进制整数 n 转换成 b 进制整数。
a,b 是十进制整数。
数据可能存在包含前导零的情况。

输出格式
输出包含一行,该行有一个整数为转换后的 b 进制数。
输出时字母符号全部用大写表示,即(01,…,9,A,B,…,F)。

数据范围
2≤a,b≤16,
给定的 a 进制整数 n 在十进制下的取值范围是 [1,2147483647]。

输入样例:
15 Aab3 7
输出样例:
210306

由于本题数据范围较小,可以通过十进制过渡一下,数据范围大的话直接用短除法(参考考研笔记(一)的最后一道题)。

秦九韶算法:常用于a进制转十进制。
一般地,一元n次多项式的求值需要经过(n+1)*n/2次乘法和n次加法,而秦九韶算法只需要n次乘法和n次加法,降低了时间复杂度。( O(n^2) --> O(n) )
img

求解流程:(1)用秦九韶算法将a进制转十进制;(2)用短除法十进制转b进制。

代码参考y总讲解:

#include <bits/stdc++.h>
using namespace std;
char iotc(int x){ // int转char
    if (x <= 9) return x+'0';
    return x-10+'A';
}

int ctoi(char c){ // char转int
    if (c <= '9') return c-'0';
    else if (c <= 'Z') return c+10-'A';
    return c+10-'a';
}

int main(){
    int a,b;
    string n;
    cin >> a >> n >> b;
    
    int t;
    for (auto i : n) t = t*a + ctoi(i); // 秦九韶算法,转十进制
    
    string ans;
    while (t) ans += t%b,t /= b; // 短除法,转b进制
    reverse(ans.begin(),ans.end());
    for (auto i : ans) cout << iotc(i);
    return 0;
}

T6--3511. 倒水问题

有三个杯子,容量分别为 A,B,C。
初始时,C 杯装满了水,而 A,B 杯都是空的。
现在在保证不会有漏水的情况下进行若干次如下操作:
将一个杯子 x 中的水倒到另一个杯子 y 中,当 x 空了或者 y 满了时就停止(满足其中一个条件才停下)。
请问,在操作全部结束后,C 中的水量有多少种可能性。

输入格式
输入包含多组测试数据。
每组数据占一行,包含三个整数 A,B,C。

输出格式
每组数据输出一个结果,占一行。

数据范围
0≤A,B,C≤4000,
每个输入最多包含 100 组数据。

输入样例:
0 5 5
2 2 4
输出样例:
2
3

把三个杯子的水量合并为一个状态,DFS所有状态,然后记录C杯子的不同容量。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL cup[3],c[3]; // cup,c分别记录当前杯子装的水和杯子容量
unordered_set<LL> states;
unordered_set<int> ans;
// 每个杯子容量不超过4位数,三个杯子共12位数,表示一个状态

LL get(){ // 计算当前杯子状态
    return cup[0]*1e8 + cup[1]*1e4 + cup[2];
}

void pour(int a,int b){ // 模拟倒水,三个杯子共有6种倒法
    LL x = min(cup[a],c[b] - cup[b]); // 倒空或倒满
    cup[a] -= x,cup[b] += x;
}

void dfs(){
    LL state = get();
    if (states.count(state)) return;
    states.insert(state);
    ans.insert(cup[2]);
    
    LL temp[3]; // 临时记录当前状态,倒水时会改变状态
    for (int i = 0;i < 3;i ++)
        for (int j = 0;j < 3;j ++){
            if (i != j){
                memcpy(temp,cup,sizeof cup);
                pour(i,j);
                dfs();
                memcpy(cup,temp,sizeof cup); // 恢复现场
            }
        }
}

int main(){
    while (cin >> c[0] >> c[1] >> c[2]){
        states.clear(); // 清空状态
        ans.clear();
        
        cup[0] = cup[1] = 0;
        cup[2] = c[2];
        dfs();
        cout << ans.size() << '\n';
    }
    return 0;
}
posted @   grant_drew  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
点击右上角即可分享
微信分享提示