1.A+B 大数相除
本题要求计算A/B,其中A是不超过1000位的正整数,B是1位正整数。你需要输出商数Q和余数R,使得A = B * Q + R成立。
输入格式:
输入在1行中依次给出A和B,中间以1空格分隔。
输出格式:
在1行中依次输出Q和R,中间以1空格分隔。
输入样例:123456789050987654321 7输出样例:
17636684150141093474 3
/*
http://pat.zju.edu.cn/contests/pat-b-practise/1017 A除以B (20) //用字符串来处理
*/
#include
#include
using namespace std;
int main()
{
string A,Q;
int B,R=0;
cin>>A>>B;
int length = A.length();
int temp = A[0]-'0';
if(temp>=B)
Q.push_back(temp/B+'0'); //避免首位出现‘0’
for(int i =1;i
2.打印素数
令Pi表示第i个素数。现任给两个正整数M <= N <= 10000,请输出PM到PN的所有素数。
#include
#include
int main()
{
using namespace std;
int m,n,count = 0;
cin >> m >> n;
for (int i = 2;count <= n;i++)
{
int temp = 0;
for (int j = 2;j <= sqrt(i);j++) //只需到根号就行
if (i % j == 0)
++temp; //这里可优化,找到即退出
if (temp == 0)
++count; //count代表第几个素数
if (count >= m && count <= n && temp == 0)
{
cout << i;
if ((count - m) % 10 == 9)
cout << endl;
else if (count != n)
cout << " ";
}
}
cout << endl;
return 0;
}
3.德才排序
链接:https://www.nowcoder.com/questionTerminal/97b6a49a85944650b2e3d0660b91c324
来源:牛客网
输入第1行给出3个正整数,分别为:N(<=105),即考生总数;L(>=60),为录取最低分数线,即德分和才分均不低于L的考生才有资格 被考虑录取;H(<100),为优先录取线——德分和才分均不低于此线的被定义为“才德全尽”,此类考生按德才总分从高到低排序;才分不到 但德分到线的一类考生属于“德胜才”,也按总分排序,但排在第一类考生之后;德才分均低于H,但是德分不低于才分的考生属于“才德兼 亡”但尚有“德胜才”者,按总分排序,但排在第二类考生之后;其他达到最低线L的考生也按总分排序,但排在第三类考生之后。 随后N行,每行给出一位考生的信息,包括:准考证号、德分、才分,其中准考证号为8位整数,德才分为区间[0, 100]内的整数。数字间以空格分隔。
输出第1行首先给出达到最低分数线的考生人数M,随后M行,每行按照输入格式输出一位考生的信息,考生按输入中说明的规则从高到低排序。当某类考生中有多人 总分相同时,按其德分降序排列;若德分也并列,则按准考证号的升序输出。
链接:https://www.nowcoder.com/questionTerminal/97b6a49a85944650b2e3d0660b91c324
来源:牛客网
#include
#include
using namespace std;
class Student
{
public:
int id, morality, ability, sum, level;
Student(int id, int morality, int ability) {
this->id = id;
this->morality = morality;
this->ability = ability;
this->sum = morality + ability;
level = 4;//默认为第4等级,可改
}
bool operator <(const Student& another)const { //set容器多级排序,等级4到1(差到好)
if(level != another.level) {
return level>another.level;
} else if(sum != another.sum) {
return another.sum>sum;
} else if(morality != another.morality) {
return another.morality>morality;
} else {
return id>another.id;
}
}
};
int main()
{
// 基本变量
int N, L, H;
cin >> N >> L >> H;
set student;
// 分类划级
for(int i=0; i> id >> morality >> ability;
Student stu(id, morality, ability);
if(stu.morality= H && stu.ability >= H) {
stu.level = 1;
} else if(stu.morality >= H) {
stu.level = 2;
} else if(morality>=ability) {
stu.level = 3;
} else {
stu.level = 4;
}
student.insert(stu); //set容器
}
// 输出结果
set::reverse_iterator iter;
cout << student.size() << endl;
for(iter=student.rbegin(); iter != student.rend(); iter++) {
cout << (*iter).id << " " << (*iter).morality << " " << (*iter).ability << endl;
}
return 0;
}
4.月饼最大售价(贪心)
链接:https://www.nowcoder.com/questionTerminal/6fc9a928c7654b0fbc37d16b8bd29ff9
来源:牛客网
每个输入包含1个测试用例。每个测试用例先给出一个不超过1000的正整数N表示月饼的种类数、以及不超过500(以万吨为单位)的正整数
D表示市场最大需求量。随后一行给出N个正数表示每种月饼的库存量(以万吨为单位);最后一行给出N个正数表示每种月饼的总售价(以亿
元为单位)。数字间以空格分隔。
#include
#include
#include
using namespace std;
struct yuebing{
double kucun;
double shoujia;
double danjia;
};
bool comparison(yuebing a,yuebing b)
{
return a.danjia>b.danjia;
}
int main()
{
double sum = 0;
int N,D;
cin>>N>>D;
vector yue(N);
for(int i =0;i<2*N;i++){
if(i<=N-1)
cin>>yue[i].kucun;
else
cin>>yue[i-N].shoujia;
}
for(int i=0;i
5.快速排序
快速排序的时间复杂度为 n*logn,好于冒泡排序,用到分治的思想。一个博客:https://blog.csdn.net/morewindows/article/details/6684558
对挖坑填数进行总结
1.i =L; j = R; 将基准数挖出形成第一个坑a[i]。
2.j--由后向前找比它小的数,找到后挖出此数填前一个坑a[i]中。
3.i++由前向后找比它大的数,找到后也挖出此数填到前一个坑a[j]中。
4.再重复执行2,3二步,直到i==j,将基准数填入a[i]中。
5.排完后左边的数比中间小,右边的数比中间大,再对左右分别递归,直到当前调整区长度不超过1
int partition(int a[], int left, int right) {
int temp = a[left]; //将最左存入临时变量,左边目前为空值
while (left < right) {
while(left < right && a[right] > temp) right--; //左移
a[left] = a[right]; //出现右边小于临界的情况,将右边的移到左边,右边目前为空值
while(left < right && a[left] <= temp) left++;
a[right] = a[left]; //出现左边大于临界的情况,将左边的移到右边,左边目前为空值
}
a[left] = temp; // temp放到left与right相遇处
return left;
}
//快速排序
void quicksort(int a[],int left,int right) {
if(left < right) { //当前区间长度不小于1
//将【left,right】按a【left】一分为二
int pos = partition(a,left,right);
quicksort(a,left,pos-1); //左子区间快排
quicksort(a,pos+1,right); //右子区间快排
}
}
6.深度优先(DFS)本质是栈
如背包问题:
7.广度优先(BFS)实质是队列
#include
#include
#include
using namespace std;
const int maxn = 100;
struct node {
int x,y; //位置
int step; //step为起点到达该位置的最少步数,即层数
}S,T,Node; //起点,终点,临时结点
int n,m; //行列
char maze[maxn][maxn]; //迷宫信息
bool inq[maxn][maxn] = {false}; //记录是否入列过
int X[4] = {0,0,1,-1}; //上下左右
int Y[4] = {1,-1,0,0};
//检测该位置是否有效
bool test(int x, int y) {
if (x >= n || x<0 || y>=m || y<0) return false;
if (maze[x][y] == '*') return false;
if (inq[x][y] == true) return false;
return true;
}
int BFS() {
queue q; //定义队列
q.push(S); //起点入队
while(!q.empty()) {
node top = q.front(); //取首元素
q.pop();
if(top.x == T.x && top.y == T.y) { //到达终点,返回步数
return top.step;
}
for(int i = 0; i< 4;i++) { //循环4次,得到四个相邻位置
int newX = top.x + X[i];
int newY = top.y + Y[i];
if(test(newX,newY)) { //位置有效
Node.x = newX,Node.y = newY;
Node.step = top.step + 1;
q.push(Node); //加入队列
inq[newX][newY] = true; //已入队
}
}
}
return -1; //无法到达终点
}
int main() {
scanf("%d%d",&n,&m);
for(int i = 0; i < n; i++) {
getchar(); //过滤换行符
for(int j = 0; j < m; j++) {
maze[i][j] = getchar();
}
maze[i][m+1] = '\0';
}
scanf("%d%d%d%d",&S.x,&S.y,&T.x,&T.y); //起点,终点坐标
S.step = 0; //初始层数为0
printf("%d\n",BFS());
return 0;
}
8.BST二叉树的建立
//先输入整个二叉树的形状,在输入一列数(不要求顺序)
#include
#include
#include
using namespace std;
const int maxn = 110;
struct node { //静态二叉树
int data;
int lchild, rchild;
} Node[maxn];
int n, in[maxn], num = 0; //n为结点数,in为中序序列,num为已经输入/输出的个数
void inOrder(int root) { //中序遍历,将排序号的序列填入二叉树系欸按
if(root == -1) {
return;
}
inOrder(Node[root].lchild);
Node[root].data = in[num++];
inOrder(Node[root].rchild);
}
void BFS(int root) { //层序遍历
queue q; //队列存地址
q.push(root);
num = 0;
while(!q.empty()) {
int now = q.front();
q.pop();
printf("%d",Node[now].data);
num++;
if(num < n) printf(" ");
if(Node[now].lchild != -1) q.push(Node[now].lchild); //左子树非空
if(Node[now].rchild != -1) q.push(Node[now].rchild);
}
}
int main() {
int lchild,rchild;
scanf("%d",&n);
for(int i = 0; i < n; i++) {
scanf("%d%d",&lchild,&rchild); // 左右孩子编号
Node[i].lchild = lchild;
Node[i].rchild = rchild;
}
for(int i = 0; i < n; i++) {
scanf("%d",&in[i]);
}
sort(in,in+n); //从小到大排,作为中序输入
inOrder(0); //输入数
BFS(0); //层序打印
return 0;
}
9.图的最短路径(Dijkstra),时间复杂度n*n,动态规划,单源,权值非负
#include
#include
using namespace std;
const int MAXV = 1000; //最大顶点数
const int INF = 1000000; //初始边权很大
int n,m,s,G[MAXV][MAXV];
int d[MAXV]; //起点到达个点的最短路径
bool vis[MAXV] = {false}; //标记是否访问过
void Dijkstra(int s) {
fill(d,d+MAXV,INF); //全设置为inf
d[s] = 0; //到到起点自身最短距离为0
for(int i = 0; i < n; i++) { //循环n次
int u = -1,min = INF; //u使d【u】最小,min存放最小的的d【u】
for(int j = 0; j < n; j++) { //找到未访问的顶点中d【】最小的
if(vis[j] == false && d[j] < min) {
u = j;
min = d[j];
}
}
if(u == -1) return; //说明剩下的点都与起点不同
vis[u] = true; //标记u已经访问
for(int v = 0;v < n; v++) { //如果v未访问,u到v能访问,且有优化空间
if(vis[v] == false && G[u][v] != INF && d[u]+G[u][v] < d[v]) {
d[v] = d[u] + G[u][v];
}
}
}
}
int main() {
int u,v,w;
scanf("%d%d%d",&n,&m,&s); //顶点个数,边数,起点
fill(G[0],G[0] + MAXV*MAXV,INF); //初始化图
for(int i = 0; i < m; i++) {
scanf("%d%d%d",&u,&v,&w); //输入u,v,及权值
G[u][v] = w;
}
Dijkstra(s);
for(int i = 0;i < n; i++) {
printf("%d",d[i]);
}
return 0;
}
核心思想:默认其余点与起点距离无限大
1.先找到离起点最近的点,访问了,访问后更新起点到剩余点的路径,看有没有更近的可能(inf->某个值)
2.在剩下的点中找最近的点,不断重复1,2
加强:打印经过结点,注意到每一次更新最短路径即意味着前驱点为当前节点,递归即可
#include
#include
using namespace std;
const int MAXV = 1000; //最大顶点数
const int INF = 1000000; //初始边权很大
int n,m,s,G[MAXV][MAXV];
int d[MAXV]; //起点到达个点的最短路径
int pre[MAXV]; // 记录前驱点
bool vis[MAXV] = {false}; //标记是否访问过
void Dijkstra(int s) {
fill(d,d+MAXV,INF); //全设置为inf
for(int i = 0; i < n; i++) pre[i] = i; //前驱点为本身
d[s] = 0; //到到起点自身最短距离为0
for(int i = 0; i < n; i++) { //循环n次
int u = -1,min = INF; //u使d【u】最小,min存放最小的的d【u】
for(int j = 0; j < n; j++) { //找到未访问的顶点中d【】最小的
if(vis[j] == false && d[j] < min) {
u = j;
min = d[j];
}
}
if(u == -1) return; //说明剩下的点都与起点不同
vis[u] = true; //标记u已经访问
for(int v = 0;v < n; v++) { //如果v未访问,u到v能访问,且有优化空间
if(vis[v] == false && G[u][v] != INF && d[u]+G[u][v] < d[v]) {
d[v] = d[u] + G[u][v];
pre[v] = u; //到v的最短路径前驱点为u
}
}
}
}
void DFS(int s, int v) {
if(v==s){
printf("%d\n",s);
return;
}
DFS(s,pre[v]);
printf("%d\n",v);
}
int main() {
int u,v,w;
scanf("%d%d%d",&n,&m,&s); //顶点个数,边数,起点
fill(G[0],G[0] + MAXV*MAXV,INF); //初始化图
for(int i = 0; i < m; i++) {
scanf("%d%d%d",&u,&v,&w); //输入u,v,及权值
G[u][v] = w;
}
Dijkstra(s);
for(int i = 0;i < n; i++) {
printf("%d",d[i]);
}
DFS(0,5);
return 0;
}
10.Flyod,多源最短路径,n*n*n
#include
#include
using namespace std;
const int INF = 100000;
const int MAXV = 200; //最大定点数,时间复杂度n3次
int n, m;
int dis[MAXV][MAXV];
void Floyd() {
for (int k = 0; k < n; k++) { //k,做中节点,放在最外,防止后面更新时前面已经访问的点无法更新
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if(dis[i][j]!= INF && dis[k][j] != INF &&
dis[i][k] + dis[k][j] < dis[i][j]) {
dis[i][j] = dis[i][k] + dis[k][j]; //找到最短路径
}
}
}
}
}
int main() {
int u,v,w;
fill(dis[0],dis[0]+MAXV*MAXV,INF);
scanf("%d%d",&n,&m); //顶点数,边数
for(int i = 0; i < n; i++) {
dis[i][i] = 0;
}
for(int i = 0; i < m; i++) {
scanf("%d%d%d",&u,&v,&w); //有向图输入
dis[u][v] = w;
}
Floyd();
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
printf("%d ",dis[i][j]);
}
printf("\n");
}
return 0;
}
11.最小生成树,prim算法
#include
#include
using namespace std;
const int MAXV = 1000; //最大顶点数
const int INF = 1000000; //初始边权很大
int n,m,s,G[MAXV][MAXV];
int d[MAXV]; //起点到达个点的最短路径
//int pre[MAXV]; // 记录前驱点
bool vis[MAXV] = {false}; //标记是否访问过
int prim() {
fill(d,d+MAXV,INF); //全设置为inf
//for(int i = 0; i < n; i++) pre[i] = i; //前驱点为本身
d[0] = 0; //到已访问集合最短距离为0
int ans = 0;
for(int i = 0; i < n; i++) { //循环n次
int u = -1,min = INF; //u使d【u】最小,min存放最小的的d【u】
for(int j = 0; j < n; j++) { //找到到已访问集合最短距离的点,d【u】为最短距离
if(vis[j] == false && d[j] < min) {
u = j;
min = d[j];
}
}
if(u == -1) return -1; //说明剩下的点都与起点不通
vis[u] = true; //标记u已经访问
ans += d[u];
for(int v = 0;v < n; v++) { //如果v未访问,u到v能访问,且已访问集合最短距离有优化空间
if(vis[v] == false && G[u][v] != INF && G[u][v] < d[v]) {
d[v] = G[u][v];
//pre[v] = u; //到v的最短路径前驱点为u
}
}
}
return ans;
}
int main() {
int u,v,w;
scanf("%d%d",&n,&m); //顶点个数,边数
fill(G[0],G[0] + MAXV*MAXV,INF); //初始化图
for(int i = 0; i < m; i++) {
scanf("%d%d%d",&u,&v,&w); //输入u,v,及权值
G[u][v] = G[v][u] = w;
}
int ans = prim();
printf("%d\n",ans);
return 0;
}
与dijkstra 算法十分相似,不同之处在于 d[i]存储的是到 点i到 已访问集合 的最短距离
总体思路:找到距离以访问集合最短的点,访问,并累计距离
形成新的以访问集合,遍历看有没有未访问点到集合的最短距离更新
寻找下一个最短点,重复。
12.动态规划DP
问题拥有最优子结构,必须有重叠子结构。
动态与分治:动态子问题重叠,是最优解。分治子问题不重叠,不一定是最优解。
动态与贪心:贪心只考虑当前,不一定最优。动态考虑全局,最优。
最大连续子序列和,时间复杂度n
,dp[i]表示以第i个元素为结尾的最大连续子序列和,最后max{dp[i]}就是答案
#include
#include
using namespace std;
const int maxn = 100;
int A[maxn],dp[maxn]; //A为原始序列,dp村以i为尾的最长子序列和
int main() {
int n;
scanf("%d",&n);
for (int i = 0; i < n; i++) {
scanf("%d",&A[i]);
}
dp[0] = A[0];
for (int i = 0; i < n; i++) {
dp[i] = max(A[i],dp[i-1]+A[i]); //状态转换方程
}
int k = 0;
for (int i = 0;i < n; i++) {
if(dp[i] > dp[k]) {
k = i;
}
}
printf("%d\n",dp[k]);
return 0;
}
13.背包
01背包:一件物品只有一个,时间复杂度O(NV)
#include
#include
using namespace std;
const int maxn = 100; //物品最大件数
const int maxv = 1000; //背包V的上限
int w[maxn],c[maxn],dp[maxn][maxv];
int main() {
int n,V;
scanf("%d%d",&n,&V);
for(int i = 0;i < n; i++) {
scanf("%d",&w[i]); //物品空间
}
for(int i = 0;i < n; i++) {
scanf("%d",&c[i]); //物品价值
}
for(int i = 0; i < n; i++) {
dp[i][0] = 0; //边界条件,容量为0时最大值为0
}
for(int v = 1; v <= V; v++) {
dp[0][v]=(v < w[0])?0:c[0]; //考虑第一件物品
}
for(int i = 1; i < n; i++) { // 状态转移方程
for(int v = 1; v <= V; v++) {
if (v >= w[i]) {
dp[i][v] = max(dp[i-1][v],dp[i-1][v-w[i]]+c[i]); // 状态转移方程
} else {
dp[i][v] = dp[i-1][v];
}
}
}
printf("%d\n",dp[n-1][V]);
return 0;
}
完全背包问题:每个物品无限多,只需改变两处
#include
#include
using namespace std;
const int maxn = 100; //物品最大件数
const int maxv = 1000; //背包V的上限
int w[maxn],c[maxn],dp[maxn][maxv];
int main() {
int n,V;
scanf("%d%d",&n,&V);
for(int i = 0;i < n; i++) {
scanf("%d",&w[i]); //物品空间
}
for(int i = 0;i < n; i++) {
scanf("%d",&c[i]); //物品价值
}
for(int i = 0; i < n; i++) {
dp[i][0] = 0; //边界条件,容量为0时最大值为0
}
for(int v = 1; v <= V; v++) {
dp[0][v]=(v < w[0])?0:(v/w[0])*c[0]; //考虑第一件物品
}
for(int i = 1; i < n; i++) { // 状态转移方程
for(int v = 1; v <= V; v++) {
if (v >= w[i]) {
dp[i][v] = max(dp[i-1][v],dp[i][v-w[i]]+c[i]);
} else {
dp[i][v] = dp[i-1][v];
}
}
}
printf("%d\n",dp[n-1][V]);
return 0;
}
多重背包问题:每件物品有固定个数,可以将每一类物品的每一件重新分类,转化为01背包问题
14.求两个字符串中连续最长子序列的长度
用hash进行比较
任意i,j区间字符的hash
#include
#include
#include
#include
#include
另一个方法,
#include
#define ll long long
#define inf 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int m[100][100];
int main(){//freopen("1.txt","r",stdin);
int i,j,k1,k2,n,ans=0,max;
string s1,s2;
getline(cin,s1);
getline(cin,s2);
k1=s1.size();
k2=s2.size();
mem(m,0);
for(i=0;ians)ans=max;
}
}//统计从左边第一列开始的斜向右下斜线的最大值
for(i=0;ians)ans=max;
}
}//统计从顶部第一行开始的斜向右下斜线的最大值
printf("%d\n",ans);
/*
for(i=0;i