USACO Section2.1 Sorting a Three-Valued Sequence 解题报告
sort3解题报告 —— icedream61 博客园(转载请注明出处)
------------------------------------------------------------------------------------------------------------------------------------------------
【题目】
给你N,而后给出N个数,每个数都是1~3中的一个。请问,要把这个数列升序排好,最少需要进行几次两两交换?
【数据范围】
1<=N<=1000
【输入样例】
9
2
2
1
3
3
3
2
3
1
【输出样例】
4
------------------------------------------------------------------------------------------------------------------------------------------------
【分析】
模拟一遍最优策略,便可得出答案,具体做法如下:
1、读入N,并读入N个数d[1]~d[N],定义最少所需交换次数s=0
2、统计下1~3分别的个数,得到1的个数num[1]和1、2的总个数num[2]。此时,便可确定最终1~3的位置分别是:
1: 1~num[1]
2: num[1]+1~num[2]
3: num[2]+1~N
3、第一轮交换,使所有的1都到位:
i=1~num[1],找!=1的位置,不存在则不妨令i==num[1]+1
当i==num[1]+1则说明所有1均到位,本轮结束。否则,
j=num[1]+1~num[2],找==1的位置,不存在则不妨令j==num[2]+1
k=num[2]+1~N,找==1的位置,不存在则不妨令j==N+1
能到这里说明需要交换一次,故而++S,
对当前i,首先争取一步换到位(即d[i]==2与d[j]换,或者d[i]==3与d[k]换),如不可能则找一个合法的换便可,不可能出现没有合法的换的情况。
4、第二轮交换,使所有的2都到位(3自然也就都到位了):
i=num[1]+1~num[2],找!=2的位置,不存在则不妨令i==num[2]+1
当i==num[2]+1则说明所有2均到位,本轮结束。否则,
j=num[2]+1~N,找==2的位置,不存在则不妨令j==N+1
能到这里说明需要交换一次,故而++S,
交换d[i]与d[j]。
5、至此,两轮交换完成,所得s即为最少所需交换次数。
------------------------------------------------------------------------------------------------------------------------------------------------
【总结】
开始没有注意到随便交换并非最优,没考虑到的就是分析中第3步的情况:在第一轮中应当先争取一步到位,这样可以减少一次交换次数。
本题还有个需要注意的地方(快排、二分等方法中也常出现这个问题),为了让下标不超出范围,要随时判断是否越界。
------------------------------------------------------------------------------------------------------------------------------------------------
【代码】
1 /* 2 ID: icedrea1 3 PROB: sort3 4 LANG: C++ 5 */ 6 7 #include <iostream> 8 #include <fstream> 9 using namespace std; 10 11 int N,d[1001]; 12 int num[4]; 13 14 int main() 15 { 16 ifstream in("sort3.in"); 17 ofstream out("sort3.out"); 18 19 in>>N; 20 for(int i=1;i<=N;++i) { in>>d[i]; ++num[d[i]]; } 21 num[2]+=num[1]; 22 23 // The situation of vector d: 24 // 1: d[1]~d[num[1]] 25 // 2: d[num[1]+1]~d[num[2]] 26 // 3: d[num[2]+1]~d[N] 27 28 int s=0; 29 for(int i=1,j=num[1]+1,k=num[2]+1;;) 30 { 31 while(i<=num[1] && d[i]==1) ++i; 32 if(i==num[1]+1) break; 33 while(j<=num[2] && d[j]!=1) ++j; 34 while(k<=N && d[k]!=1) ++k; 35 ++s; 36 if(d[i]==2 && j<=num[2]) swap(d[i],d[j]); else if(d[i]==3 && k<=N) swap(d[i],d[k]); // 一步换到位更优 37 else if(j<=num[2]) swap(d[i],d[j]); else swap(d[i],d[k]); // 无法一步到位,那就换个合法的就行 38 } 39 for(int i=num[1]+1,j=num[2]+1;;) 40 { 41 while(i<=num[2] && d[i]==2) ++i; 42 if(i==num[2]+1) break; 43 while(j<=N && d[j]!=2) ++j; 44 swap(d[i],d[j]); ++s; 45 } 46 47 out<<s<<endl; 48 49 in.close(); 50 out.close(); 51 return 0; 52 }
posted on 2015-03-14 10:40 IceDream61 阅读(189) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端