给定一个迷宫,指明起点和终点,找出从起点出发到终点的有效可行路径,就是迷宫问题(maze problem)
迷宫可以以二维数组来存储表示。0表示通路,1表示障碍。注意这里规定移动可以从上、下、左、右四方方向移动。坐标以行和列表示,均从0开始,给定起点(0,0)和终点(4,4),迷宫表示如下:
左图每个方块表示一个状态,浅蓝色的表示遍历了该状态。
广度优先搜索即是按层数一层一层来遍历,先将一层全部扩展,然后再进行下一层。
利用队列先进先出(FIFO)的性质恰好可以来完成这个任务
对应的队列的情况:
具体过程:
1 每次取出队列首元素(初始状态),进行拓展
2 然后把拓展所得到的可行状态都放到队列里面
3 将初始状态删除
4 循环执行以上三步直到找到目标状态或者队列为空。
#include <cstdio> #include <iostream> #include <cstring> #include <cstdlib> #include <queue> using namespace std; int mp[10][10]; bool inq[10][10];//passed set true struct node{ int x,y; node(int x=0,int y=0):x(x),y(y) {} }; queue<node> q; node frm[10][10]; int dx[4]={0,1,0,-1}; int dy[4]={-1,0,1,0}; bool bfs(){ q.push(node(1,1)); inq[1][1]=true; frm[1][1]=node(0,0); while (!q.empty()){ node now = q.front(); q.pop(); if (now.x==5 && now.y==5){ return true; } for(int i=0;i<4;i++){ int tx=now.x+dx[i],ty=now.y+dy[i]; if (!inq[tx][ty] && mp[tx][ty]==0){ inq[tx][ty]=true; q.push(node(tx,ty)); frm[tx][ty]=now; } } } return false; } void printans(int x,int y){ if (x==0 && y==0) return; printans(frm[x][y].x,frm[x][y].y); printf("(%d, %d)\n",x-1,y-1); } int main(){ for (int i=0;i<=6;i++){ for (int j=0;j<=6;j++){ mp[i][j]=-1; } } for (int i=1;i<=5;i++){ for (int j=1;j<=5;j++){ scanf("%d",&mp[i][j]); } } bfs(); printans(5,5); return 0; }
Q&A:
什么是二分法呢?
其实一直以来,在我的印象当中就是高中时候求解二元一次方程组解的时候所使用的算法。
也是现代计算器进行计算的原理。(即一直>>1[除以2]直到答案符合精度)
现在,我将通过系统的学习来为大家讲述二分法的更深入的地方。
Time limit : 1 s | Memory limit : 32 mb |
---|---|
Submitted : 6 | Accepted : 2 |
64bit Integer Format : %lld |
---|
#include <stdio.h> #include <stdlib.h> #include <cstdio> struct info{ double val; int pos; }; int amount(info a[],int n) { int i,j; for(i=0;i<n;i++) { for(j=i+1;j<n;j++) { if(a[j].val>a[i].val) { double t; t = a[i].val; a[i].val=a[j].val; a[j].val=t; int tt; tt=a[i].pos; a[i].pos=a[j].pos; a[j].pos=tt; } } } return 0; } int main() { int M,N; int i; while(1) { scanf("%d %d",&M,&N); if(M==-1&&N==-1) break; info price[N]={0}; int F[N]={0},J[N]={0}; for(i=0;i<N;i++) { scanf("%d %d",&J[i],&F[i]); price[i].val=(double)J[i]/F[i]; price[i].pos=i; } amount(price,N); double output=0; for(i=0;i<N;i++) { if(M>=F[price[i].pos]) { output+=price[i].val*F[price[i].pos]; M-=F[price[i].pos]; } else if(M>0&&M<F[price[i].pos]) { output+=price[i].val*M; M=0; break; } } printf("%.3lf\n",output); } return 0; }
然而在oj里面。。。Runtime Error
没办法啊,只好看看哪里可以改进
2.sort
#include<stdio.h> #include<stdlib.h> #include<algorithm> using namespace std; const int MAXN = 1010; struct node { double j,f; double r; }a[MAXN]; /* int cmp(const void *a,const void *b)//从大到小排序 { struct node *c=(node *)a; struct node *d=(node *)b; if(c->r > d->r) return -1; else return 1; } */ bool cmp(node a,node b) { return a.r > b.r; } int main() { int N; double M; double ans; while(scanf("%lf%d",&M,&N)) { if(M==-1&&N==-1) break; for(int i=0;i<N;i++) { scanf("%lf%lf",&a[i].j,&a[i].f); a[i].r=(double)a[i].j/a[i].f; } //qsort(a,N,sizeof(a[0]),cmp); sort(a,a+N,cmp); ans=0; for(int i=0;i<N;i++) { if(M>=a[i].f) { ans+=a[i].j; M-=a[i].f; } else { ans+=(a[i].j/a[i].f)*M; break; } } printf("%.3lf\n",ans); } return 0; }
key3:without sort:
#include<stdio.h> #include<stdlib.h> const int MAXN = 1010; struct node { double j,f; double r; }a[MAXN]; int cmp(const void *a,const void *b)//从大到小排序 { struct node *c=(node *)a; struct node *d=(node *)b; if(c->r > d->r) return -1; else return 1; } int main() { int N; double M; double ans; while(scanf("%lf%d",&M,&N)) { if(M==-1&&N==-1) break; for(int i=0;i<N;i++) { scanf("%lf%lf",&a[i].j,&a[i].f); a[i].r=(double)a[i].j/a[i].f; } qsort(a,N,sizeof(a[0]),cmp); ans=0; for(int i=0;i<N;i++) { if(M>=a[i].f) { ans+=a[i].j; M-=a[i].f; } else { ans+=(a[i].j/a[i].f)*M; break; } } printf("%.3lf\n",ans); } return 0; }
吃糖果问题
复杂方法:
#include<stdio.h> #include<math.h> #include<stdlib.h> main() { int i,t,j,N,f[50]={0}; scanf("%d",&t); for(i=0;i<t;i++) { scanf(" %d",&N); for(j=0;j<N;j++) { scanf(" %d",&f[j]); } int k; for(j=0;j<N;j++) { for(k=0;k<N;k++) { if(f[i]<f[i+1]) { int middle = f[i]; f[i]=f[i+1]; f[i+1]=middle; } } } int flag=f[0]; for(k=0;k<N;k++) { flag=flag-f[k+1]; } if(flag>=2) printf("No\n"); else printf("Yes\n"); } }
简便算法:
# include<stdio.h> int main() { long T, N; double candy, max,sum; scanf("%d",&T); while(T--) { scanf("%d", &N); max = sum = 0; while(N--) { scanf("%lf", &candy); max = max > candy ? max : candy; sum += candy; } sum -= max; if(max <= sum + 1) printf("Yes\n"); else printf("No\n"); } }
a very interesting game:
#include <stdlib.h> #include <stdio.h> #include <conio.h> //应用 getch() 函数 函数用途:从控制台读取一个字符,但不显示在屏幕上 #include <string.h> //定义棋盘大小 标准 15*15棋盘 #define MAXIMUS 15 //存储对局信息 二维数组 int p[MAXIMUS][MAXIMUS]; //输出缓冲器 纵横分别 15*2+1个字符图标 15*4+3个字符图标 //目的:1、显示方形光标 2、打印棋盘(单字符长宽不等) char buff[MAXIMUS*2+1][MAXIMUS*4+3]; //当前光标位置 int Cx,Cy; //当前走子的玩家,1代表黑,2代表白 int Now; //当前写入缓冲器的行数和列数位置 int wl,wp; //在棋盘中央显示的文字信息 char* showText; //回合数 int count; //修改过的字符串复制函数,会忽略末端的\0 char* Copy(char* strDest,const char* strSrc); //初始化一个对局函数 void Initialize();//Initialize:初始化 //获得棋盘中指定坐标交点位置的字符,通过制表符拼成棋盘 char* getStyle(int i,int j); //获得指定坐标交点位置左上格的样式,通过制表符来模拟光标的显示 //getCurse:获得图案 char* getCurse(int i,int j); //向缓冲器写入字符串 void write(char* c); //缓冲器写入位置提行 void ln(); //将缓冲器内容输出到屏幕 void Display(); //将整个棋盘算出并储存到缓冲器,然后调用Display函数显示出来 void Print(); //在当前光标位置走子,如果非空,则返回0表示失败 int Put(); //胜负检查,即判断当前走子位置有没有造成五连珠的情况 int Check(); //进行整个对局,返回赢家信息 int RunGame(); //主函数 int main() { //设置标题 system("title 简易五子棋 ——翻转课堂"); //设置窗口大小 system("mode con cols=63 lines=32"); /*设置颜色 *system("color 0A"); 其中color后面的0是背景色代号,A是前景色代号。各颜色代码如下: *0=黑色 1=蓝色 2=绿色 3=湖蓝色 4=红色 5=紫色 6=黄色 7=白色 8=灰色 9=淡蓝色 *A=淡绿色 B=淡浅绿色 C=淡红色 D=淡紫色 E=淡黄色 F=亮白色 */ system("color 72"); //循环执行游戏 while(1) { RunGame(); } } //修改过的字符串复制函数,会忽略末端的\0 主要考虑到Dispaly函数 char* Copy(char* strDest,const char* strSrc) { char* strDestCopy = strDest; while (*strSrc!='\0') { *strDest++=*strSrc++; } return strDestCopy; } //进行整个对局,返回赢家信息(虽然有用上) int RunGame() { //输入变量 int input; //赢家信息 int victor; //初始化对局 Initialize(); //开始无限回合的死循环,直到出现胜利跳出 while(1) { //打印棋盘 Print(); //等待键盘按下一个字符 //getch 从控制台读取一个字符,但不显示在屏幕上 input=getch(); //如果是ESC则退出程序,ESC的ASCLL码为27 if(input==27) { //正常退出 exit(0); } //如果是空格则开始走子 else if(input==0x20) { //如果走子成功则判断胜负 //put判断当前位置能否走子,即是否已经走过子 if(Put()) { victor=Check(); //轮换当前走子玩家,3-1=2,3-2=1 Now=3-Now; //对局数+1 count++; //如果黑方达到胜利,显示提示文字并等待一次按键,返回胜利信息 if(victor==1) { showText="黑方获得了胜利!"; //重新输出棋盘 且中间为showText文字 Print(); /*When reading a function key or an arrow key, *each function must be called twice; *the first call returns 0 or 0xE0, *and the second call returns the actual key code. */ if(getch()==0xE0) { getch(); } return Now; //并无实际意义,只是结束循环 } //如果白方达到胜利,显示提示文字并等待一次按键,返回胜利信息 else if(victor==2) { showText="白方获得了胜利!"; Display(); if(getch()==0xE0) { getch(); } return Now; } //如果回合数达到了棋盘总量,即棋盘充满,即为平局 else if(count==MAXIMUS*MAXIMUS) { showText="平局!"; Display(); if(getch()==0xE0) { getch(); } return 0; } } } //如果按下的是方向键,会填充两次输入,第一次为0xE0表示按下的是控制键 else if(input==0xE0) { //获得第二次输入信息 input=getch(); //判断方向键方向并移动光标位置 switch(input) { case 0x4B: Cx--; break; case 0x48: Cy--; break; case 0x4D: Cx++; break; case 0x50: Cy++; break; } //如果光标位置越界则移动到对侧 if(Cx<0)Cx=MAXIMUS-1; if(Cy<0)Cy=MAXIMUS-1; if(Cx>MAXIMUS-1)Cx=0; if(Cy>MAXIMUS-1)Cy=0; } } } //初始化一个对局函数 void Initialize() { //循环变量 int i,j; //重置显示信息 showText=""; //回合数归零 count=0; //重置对局数据 for(i=0;i<MAXIMUS;i++) { for(j=0;j<MAXIMUS;j++) { p[i][j]=0; //各处走子归零 } } //重置光标到中央 Cx=Cy=MAXIMUS/2; //重置当前为黑方 Now=1; } //获得棋盘中指定坐标交点位置的字符,通过制表符拼成棋盘 char* getStyle(int i,int j) { //1为黑子 if(p[i][j]==1) return "●"; //2为白子 else if(p[i][j]==2) return "○"; //以下为边缘棋盘样式 else if(i==0&&j==0) return "┏"; else if(i==MAXIMUS-1&&j==0) return "┓"; else if(i==MAXIMUS-1&&j==MAXIMUS-1) return "┛"; else if(i==0&&j==MAXIMUS-1) return "┗"; else if(i==0) return "┠"; else if(i==MAXIMUS-1) return "┨"; else if(j==0) return "┯"; else if(j==MAXIMUS-1) return "┷"; //中间的空位 return "┼"; } //获得指定坐标交点位置左上格的样式,通过制表符来模拟光标的显示 char* getCurse(int i,int j) { if(i==Cx) { if(j==Cy) return "┏"; else if (j==Cy+1) return "┗"; } else if(i==Cx+1) { if(j==Cy) return "┓"; else if (j==Cy+1) return "┛"; } //如果不在光标附近则为空 return " "; } //向缓冲器写入字符串 void write(char* c) { //字符串复制 (地址,地址),修改 wl、wp 处的字符为*c所指字符 strcpy(buff[wl]+wp,c); //移至下一列 通过ln函数移动至下一行 wp+=strlen(c); } //缓冲器写入位置 提行 void ln() { //行数+1 wl+=1; //列数归0 wp=0; } //将缓冲器内容输出到屏幕 void Display() { //循环变量,中间文字信息的长度 //showText 在RunGame函数里写出 int i,l=strlen(showText); //算出中间文字信息居中显示所在的横坐标位置 int Offset=MAXIMUS*2+2-l/2; //如果位置为奇数,则移动到偶数,避免混乱 if(Offset%2==1) { Offset--; } //讲中间文字信息复制到缓冲器 //由于 没有 \0 可以顺利输出缓冲期中showText后的其余字节 Copy(buff[MAXIMUS]+Offset,showText); //如果中间文字长度为半角奇数,则补上空格,避免混乱 if(l%2==1) { *(buff[MAXIMUS]+Offset+l)=0x20; //空格的ASCLL码 为16进制 0x20 } //清理屏幕,准备写入 system("cls"); //system("CLS")可以实现清屏操作。 //循环写入每一行 for(i=0;i<MAXIMUS*2+1;i++) { printf("%s",buff[i]); //buff[i] 在Print函数里写入 //写入完每一行需要换行 if(i<MAXIMUS*2) printf("\n"); } } //将整个棋盘算出并储存到缓冲器(即buff 二维字符数组,寄存各位置字符),然后调用Display函数显示出来 //Print 为 写入各位置buff字符 但并不输出 Display 显示 void Print() //Print 之后 Display { //循环变量 int i,j; wl=0; wp=0; //写入出交点左上角的字符,因为需要打印棋盘右下角,所以可以横纵各多一次循环 for(j=0;j<=MAXIMUS;j++) //第j行 j为行数 { for(i=0;i<=MAXIMUS;i++) //第i列 i为列数 { //写入左上角字符 write(getCurse(i,j)); //判断i,j是否在光标位置 如果不是 getCurse函数返回“ ”填充棋盘 //如果是棋盘上下边缘则没有连接的竖线,用空格填充位置 if(j==0||j==MAXIMUS) { if(i!=MAXIMUS) // != 暂无特殊含义 write(" "); //最上 最下 各空一行 } //如果在棋盘中间则用竖线承接上下 else { //左右边缘的竖线更粗 if(i==0||i==MAXIMUS-1) write("┃"); //中间的竖线 else if(i!=MAXIMUS) write("│"); } } //如果是最后一次循环,则只需要处理边侧字符,交点要少一排 if(j==MAXIMUS) { break; } //提行开始打印交点内容 ln(); //用空位补齐位置 左侧一列 补为空 write(" "); //按横坐标循环正常的次数 for(i=0;i<MAXIMUS;i++) { //写入交点字符 write(getStyle(i,j)); //如果不在最右侧则补充一个横线承接左右 if(i!=MAXIMUS-1) { if(j==0||j==MAXIMUS-1) { //上下边缘的横线更粗 write("━"); } else { //中间的横线 write("—"); } } } //写完一行后提行 ln(); } //将缓冲器内容输出到屏幕 Display(); } //在当前光标位置走子,如果非空,则返回0表示失败 int Put() { if(p[Cx][Cy]==0) { //改变该位置数据 p[Cx][Cy]=Now; //标记当前走子:走子位置写入1/2 //返回1表示成功 return 1; } else { return 0; } } //胜负检查,即判断当前走子位置有没有造成五连珠的情况 int Check() { //累计横竖正斜反斜四个方向的连续相同棋子数目 int w=1,x=1,y=1,z=1,i; //向下检查 for(i=1;i<5;i++)if(Cy+i<MAXIMUS&&p[Cx][Cy+i]==Now)w++;else break; //向上检查 for(i=1;i<5;i++)if(Cy-i>0&&p[Cx][Cy-i]==Now)w++;else break; //若果达到5个则判断当前走子玩家为赢家 if(w>=5)return Now; //向右检查 for(i=1;i<5;i++)if(Cx+i<MAXIMUS&&p[Cx+i][Cy]==Now)x++;else break; //向左检查 for(i=1;i<5;i++)if(Cx-i>0&&p[Cx-i][Cy]==Now)x++;else break; //若果达到5个则判断当前走子玩家为赢家 if(x>=5)return Now; //向右下检查 for(i=1;i<5;i++)if(Cx+i<MAXIMUS&&Cy+i<MAXIMUS&&p[Cx+i][Cy+i]==Now)y++;else break; //向左上检查 for(i=1;i<5;i++)if(Cx-i>0&&Cy-i>0&&p[Cx-i][Cy-i]==Now)y++;else break; //若果达到5个则判断当前走子玩家为赢家 if(y>=5)return Now; //向右上检查 for(i=1;i<5;i++)if(Cx+i<MAXIMUS&&Cy-i>0&&p[Cx+i][Cy-i]==Now)z++;else break; //向左下检查 for(i=1;i<5;i++)if(Cx-i>0&&Cy+i<MAXIMUS&&p[Cx-i][Cy+i]==Now)z++;else break; //若果达到5个则判断当前走子玩家为赢家 if(z>=5)return Now; //若没有检查到五连珠,则返回0表示还没有玩家达成胜利 return 0; }
Write before:
Have you ever feel amazed when you settle to think about the principles when you entering your password?
I haver always been curious about that.
So lets' uncover the mystery now!
#include <stdio.h> #include <conio.h> #define MAX_PSD_LEN 20 char PassWord[MAX_PSD_LEN],*p=PassWord,ch; int count=0; main() { ch=getch(); while(ch!=13&&count<MAX_PSD_LEN-1) /*当按下回车键或密码长度达到19,则退出循环*/ { if(ch==8) /*如果按下的是向前删除键,则...*/ { if(count) /*如果密码串中字符数大于零,则向前删除一个字符*/ { p--; count--; printf("\b ");/*光标回退一格,将星号(*)改为空格*/ printf("\b"); /*光标重新回退一格*/ } } else if((ch<='Z'&&ch>='A')||(ch<='z'&&ch>='a')||(ch<='9'&&ch>='0')) /*如果输入的是密码的有效字符*/ { printf("*"); /*输出一个星号*/ count++; *p=ch; /*记录密码内容*/ p++; } ch=getch(); /*等待输入下一个字符*/ } PassWord[count]=0; printf("\nThe Password you input is:\n"); printf("%s\n",PassWord); }
1.编程统计候选人的得票数。设有3个候选人zhang、li、wang(候选人姓名不区分大小写),10个选民,选民每次输入一个得票的候选人的名字,若选民输错候选人姓名,则按废票处理。选民投票结束后程序自动显示各候选人的得票结果和废票信息。要求用结构体数组candidate表示3个候选人的姓名和得票结果。
例如:
Input vote 1:li
Input vote 2:li
Input vote 3:Zhang
Input vote 4:wang
Input vote 5:zhang
Input vote 6:Wang
Input vote 7:Zhang
Input vote 8:wan
Input vote 9:li
Input vote 10:lii
Election results:
li:3
zhang:3
wang:2
Wrong election:2
#include<stdio.h> #include<string.h> #define TheNumberOfTheELECTORATE 10 #define TheNumberOfTheCANDIDATE 3 struct candidate { char name[20]; int count; }CANDIDATE[3]={"li",0,"zhang",0,"wang",0}; int main() { int i,j,flag=1,wrong=0; char name[20]; for(j=1;j<=TheNumberOfTheELECTORATE;j++) { printf("Input vote %d:",j); scanf("%s",name); strlwr(name); flag=1; for(i=0;i<TheNumberOfTheCANDIDATE;i++) { if(strcmp(name,CANDIDATE[i].name)==0) { CANDIDATE[i].count++; flag=0; } } if(flag) { wrong++; flag=0; } } printf("Election results:\n"); for(i=0;i<TheNumberOfTheCANDIDATE;i++) { printf("%8s:%d\n",CANDIDATE[i].name,CANDIDATE[i].count); } printf("Wrong election:%d\n",wrong); return 0; }
1.
//编程实现找出字符串中最大字符元素并输出该元素及其对应的ASCII值. //****要求输入提示信息为: //"Input a string:\n" //****输出格式要求为: //"The largest character of \"%s\" is \'%c\' ,The ASCII is %d." #define N 100 #include<stdio.h> #include<string.h> main() { printf("Input a string:\n"); char c[N]; gets(c); char d=c[0]; int i; for(i=1;i<=strlen(c);i++) { if(d<c[i]) d=c[i]; } printf("The largest character of \"%s\" is \'%c\' ,The ASCII is %d.",c,d,d); }
2.
按如下函数原型编程计算并输出n×n阶矩阵的转置矩阵。其中,n由用户从键盘输入。已知n值不超过10。
void Transpose(int (*a)[N], int n);
void Swap(int *x, int *y);
void InputMatrix(int (*a)[N], int n);
void PrintMatrix(int (*a)[N], int n);
输入提示信息:"Input n:"
输入格式:"%d"
输入提示信息:"Input %d*%d matrix:\n"
输出提示信息:"The transposed matrix is:\n"
输出格式:"%d\t"
#include <stdio.h> #define N 10 void Swap(int *x, int *y); void Transpose(int (*a)[N], int n); void InputMatrix(int (*a)[N], int n); void PrintMatrix(int (*a)[N], int n); int main() { int s[N][N], n; printf("Input n:"); scanf("%d", &n); InputMatrix(s, n); Transpose(s, n); printf("The transposed matrix is:\n"); PrintMatrix(s, n); return 0; } /* 函数功能:交换两个整型数的值 */ void Swap(int *x, int *y) { int temp; temp = *x; *x = *y; *y = temp; } /* 函数功能:计算n*n矩阵的转置矩阵 */ void Transpose(int (*a)[N], int n) { int i, j; for (i = 0; i < n; i++) { for (j = i; j < n; j++) { Swap(*(a + i) + j, *(a + j) + i); } } } /* 函数功能:输入n*n矩阵的值 */ void InputMatrix(int (*a)[N], int n) { int i, j; printf("Input %d*%d matrix:\n", n, n); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { scanf("%d", *(a + i) + j); } } } /* 函数功能:输出n*n矩阵的值 */ void PrintMatrix(int (*a)[N], int n) { int i, j; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { printf("%d\t", *(*(a + i) + j)); } printf("\n"); } }
我的代码
#include<stdio.h> #define N 10 void Transpose(int (*a)[N], int n) { int i,j; for(i=0; i<n; i++) { for(j=i+1; j<n; j++) { Swap(*(a+i)+j,*(a+j)+i); } } } void Swap(int *x, int *y) { int temp; temp=*x; *x=*y; *y=temp; } void InputMatrix(int (*a)[N], int n) { printf("Input %d*%d matrix:\n",n,n); int i,j; for(i=0; i<n; i++) { for(j=0; j<n; j++) { scanf("%d",*(a+i)+j); } } } void PrintMatrix(int (*a)[N], int n) { int i,j; for(i=0; i<n; i++) { for(j=0; j<n; j++) { printf("%d\t",*(*(a+i)+j)); } printf("\n"); } } main() { int n=100,s[N][N]= {0}; printf("Input n:"); do { scanf("%d",&n); } while(n>10); InputMatrix(s,n); Transpose(s,n); printf("The transposed matrix is:\n"); PrintMatrix(s,n); return 0; }
我个人认为,我的代码比答案还要简单,因为减少了一步不必要的计算,因此,运算时间会短一些。效率会高些!
for(j=i; j<n; j++)
其实如果要直接输出转置矩阵,还有更简便的做法:
即:输出先j后i!无论是代码量还是计算量,都少了一大截!!!
#include<stdio.h> #define N 10 void InputMatrix(int (*a)[N], int n) { printf("Input %d*%d matrix:\n",n,n); int i,j; for(i=0; i<n; i++) { for(j=0; j<n; j++) { scanf("%d",*(a+i)+j); } } } void PrintMatrix(int (*a)[N], int n) { int i,j; for(i=0; i<n; i++) { for(j=0; j<n; j++) { printf("%d\t",*(*(a+j)+i)); } printf("\n"); } } main() { int n=100,s[N][N]= {0}; printf("Input n:"); do { scanf("%d",&n); } while(n>10); InputMatrix(s,n); printf("The transposed matrix is:\n"); PrintMatrix(s,n); return 0; }
题外话:
有句mmp今天一定要讲。这种题出的简直就是多此一举
因为
我们可以认为: int (*a)[]=int a [][]
int b[4][4]={0}; int (*a)[4]=b; int b[4][4]={0}; int *a[4]; a[0]=b[0]; 就是说 int *a[n]是指针数组(也就是说其本质上是数组,但里面存放的都是指针) int (*a)[n]是数组指针(本质上是一个指针,而且是一个指向数组的指针)
第一部分:
a的类型是int[4],a[0]的类型是int;a是指向int[4]的指针
int (*a)[4]=b;指的是a指向的是int [4],然后把b的第一行地址赋给他
就是直接拷贝了首元素地址
第二部分很好理解
就是把b[0]的首行地址给a[4];
其实这种题完全可以用数组的方法做,看起来更加简洁,效率也几乎一样
#include<stdio.h> #include<string.h> #define N 4 int convertmatrix(int m[N][N]) { int i,j,temp; for(i=0;i<N;i++) { for(j=i+1;j<N;j++) { temp=m[i][j]; m[i][j]=m[j][i]; m[j][i]=temp; } } return 0; } int main() { int matrix[N][N]; int i,j; printf("请输入一个%d*%d的矩阵:\n",N,N); for(i=0;i<N;i++) { for(j=0;j<N;j++) { scanf("%d",&matrix[i][j]); } } convertmatrix(matrix); for(i=0;i<N;i++) { for(j=0;j<N;j++) { printf("%-3d",matrix[i][j]); } printf("\n"); } return 0; }
用指针编简直就是在浪费时间
所以。。。。
还有一种做法:
#include<stdio.h> #include<string.h> #define N 4 int convertmatrix(int m[N][N]) { int i,j,temp; for(i=0;i<N;i++) { for(j=i+1;j<N;j++) { temp=m[i][j]; m[i][j]=m[j][i]; m[j][i]=temp; } } return 0; } int main() { int matrix[N][N]; int i,j; printf("请输入一个%d*%d的矩阵:\n",N,N); for(i=0;i<N;i++) { for(j=0;j<N;j++) { scanf("%d",&matrix[i][j]); } } convertmatrix(matrix); for(i=0;i<N;i++) { for(j=0;j<N;j++) { printf("%-3d",matrix[i][j]); } printf("\n"); } return 0; }
另外一个比较类似的问题:
用指向一维数组的指针变量即二维数组的行指针作为函数参数,实现矩阵转置。按如下函数原型编程计算并输出m×n阶矩阵的转置矩阵。其中,m和n的值由用户从键盘输入。已知m和n的值都不超过10。
void Transpose(int (*a)[N], int (*at)[M], int m, int n);
void InputMatrix(int (*a)[N], int m, int n);
void PrintMatrix(int (*at)[M], int n, int m);
输入提示信息:"Input m, n:"
输入格式:"%d,%d"
输入提示信息:"Input %d*%d matrix:\n"
输出提示信息和格式:"The transposed matrix is:\n"
输出格式:"%d\t"
#include<stdio.h> #define M 10 #define N 10 void Transpose(int (*a)[N], int (*at)[M], int m, int n); void InputMatrix(int (*a)[N], int m, int n); void PrintMatrix(int (*at)[M], int n, int m); int main() { int s[M][N],st[N][M],m,n; printf("Input m, n:"); scanf("%d,%d",&m,&n); InputMatrix(s,m,n); Transpose(s,st,m,n); printf("The transposed matrix is:\n"); PrintMatrix(st,n,m); return 0; } void Transpose(int (*a)[N], int (*at)[M], int m, int n) { int i,j; for(i=0;i<m;i++) { for(j=0;j<n;j++) { *(*(at+j)+i)=*(*(a+i)+j); } } } void InputMatrix(int (*a)[N], int m, int n) { int i,j; printf("Input %d*%d matrix:\n",m,n); for(i=0;i<m;i++) { for(j=0;j<n;j++) { scanf("%d",*(a+i)+j); } } } void PrintMatrix(int (*at)[M], int n, int m) { int i,j; for(i=0;i<n;i++) { for(j=0;j<m;j++) { printf("%d\t",*(*(at+i)+j)); } printf("\n"); } }
3.
从键盘任意输入一个整型表示的月份值,用指针数组编程输出该月份的英文表示,若输入的月份值不在1~12之间,则输出“Illegal month”。
**输入格式要求:"%d" 提示信息:"Input month number:"
**输出格式要求:"month %d is %s\n"
"Illegal month", "January", "February", "March", "April", "May", "June", "July", August", "September", "October", "November", "December"
程序运行示例1如下:
Input month number:5
month 5 is May
程序运行示例2如下:
Input month number:13
Illegal month
#include<stdio.h> int main() { int n; static char*monthName[]={"Illegal month", "January", "February", "March", "April", "May", "June", "July", “August", "September", "October", "November", "December"}; printf("Input month number:"); scanf("%d",&n); if((n<=12)&&(n>=1)) printf("month %d is %s\n",n,monthName[n]); else printf("%s\n",monthName[0]); return 0; }
4.
#include <stdio.h> #define ROW 2 #define COL 3 void main() { int a[ROW][COL], b[COL][ROW], c[ROW][ROW], i, j,k; printf("Input 2*3 matrix a:\n"); for (i=0; i<ROW ;i++) { for (j=0; j<COL; j++) { scanf("%d", &a[i][j]); } } printf("Input 3*2 matrix b:\n"); for (i=0; i<COL; i++) { for (j=0; j<ROW; j++) { scanf("%d", &b[i][j]); } } for (i=0; i<ROW; i++) { for (j=0; j<ROW; j++) { c[i][j] = 0 ; for (k=0; k<COL; k++) { c[i][j] = c[i][j]+a[i][k]*b[k][j] ; } } } printf("Results:\n"); for (i=0; i<ROW; i++) { for (j=0; j<ROW; j++) { printf("%6d", c[i][j]); } printf("\n") ; } }
本次内容到此全部结束
Before we go:
Hello大家好,好长时间没写程序了,不知道是不是手生了还是题目越来越难了,零分我真是越来越多了。
所以我将这些程序分享给大家
希望大家少走点弯路,也避免我以后忘记这些东西。
1.假设有40个学生被邀请来给餐厅的饮食和服务质量打分,分数划分为1~10这10个等级(1表示最低分,10表示最高分),编程统计并按如下格式输出餐饮服务质量调查结果。
Grade Count Histogram
1 5 *****
2 10 **********
3 7 *******
...
**输入格式要求:"%d" 提示信息:"Input the feedbacks of 40 students:\n" "input error!\n"
**输出格式要求:"Feedback\tCount\tHistogram\n" "%8d\t%5d\t"
程序运行示例如下:
Input the feedbacks of 40 students:
10 9 10 8 7 6 5 10 9 8
8 9 7 6 10 9 8 8 7 7
6 6 8 8 9 9 10 8 7 7
9 8 7 9 7 6 5 9 8 7
Feedback Count Histogram
1 0
2 0
3 0
4 0
5 2 **
6 5 *****
7 9 *********
8 10 **********
9 9 *********
10 5 *****
#include<stdio.h> main(){ printf("Input the feedbacks of 40 students:\n"); int i,s[40]={0}; int ret; for(i=0;i<40;i++){ ret =scanf("%d",&s[i]); if(ret!=1||s[i]<1||s[i]>10) { i--; printf("input error!\n"); } } printf("Feedback\tCount\tHistogram\n"); int a[10]={0},j; for(i=0;i<40;i++){ for(j=0;j<10;j++) { if(s[i]==j+1) a[j]++; } } for(i=0;i<10;i++) { printf("%8d\t%5d\t",i+1,a[i]); for(j=0;j<a[i];j++) { printf("*"); } printf("\n"); } }
2.如果一个正整数等于其各个数字的立方和,则该数称为阿姆斯特朗数(亦称为自恋性数)。如407=4^3+0^3+7^3就是一个阿姆斯特朗数。试编程求1000内的所有3位数的阿姆斯特朗数。
**输出格式要求:"There are following Armstrong number smaller than 1000:\n" " %d "
程序运行示例如下:
There are following Armstrong number smaller than 1000:
153 370 371 407
\\这道题比较简单,但是要注意不要使用pow函数,否则会有精度误差! #include<stdio.h> #include<stdio.h> main() { printf("There are following Armstrong number smaller than 1000:\n"); int i,j,k,f; int a[10]={0,1,2,3,4,5,6,7,8,9},b[10]={0,1,2,3,4,5,6,7,8,9},c[10]={0,1,2,3,4,5,6,7,8,9}; for(i=0;i<10;i++) { for(j=0;j<10;j++) { for(k=0;k<10;k++) { if(a[i]*100+b[j]*10+c[k]==powl(i,3)+powl(j,3)+powl(k,3)&&a[i]*100+b[j]*10+c[k]>1) printf(" %d ",a[i]*100+b[j]*10+c[k]); } } } }
3.输入一个以回车结束的字符串(少于10个字符),它由数字字符组成,将该字符串转换成整数后输出。
**输入提示信息:"Enter a string: "
**输出格式要求:"digit = %d\n"
程序运行示例如下:
Enter a string: 123
digit = 123
#include <stdio.h> int main(void) { int i, n; char s[10]; /* 输入字符串 */ printf("Enter a string: "); /* 输入提示 */ i = 0; while ((s[i] = getchar( )) != '\n') i++; s[i] = '\0'; /* 将字符串转换为整数 */ n = 0; for (i = 0; s[i] != '\0'; i++) if (s[i] <= '9' && s[i] >= '0') n = n * 10 + (s[i] - '0'); else /* 遇非数字字符结束转换 */ break; printf("digit = %d\n", n); return 0; }
4.走台阶
楼梯有10阶台阶,上楼可以一步上1阶,也可以1步上2阶,编程计算10阶台阶总共有多少走法.
提示:可以递推计算,如1阶台阶总共一种走法,2阶台阶总共2走法,3阶台阶总共3种走法,直到计算出10阶台阶走法.
输入格式:无
输出格式:"Result=%d"
这类题一看就知道是与递归有关的问题,因此我们很容易用递归解决这道题
#include<stdio.h> int f( int n ) { if ( n == 1 ) { return 1; } else if ( n == 2 ) { return 2; } else { return f(n-1) + f(n-2); } } int main() { int num = f( 10 ); printf("Result=%d",num); return 0; }
5.选择排序法。
用选择排序法将N(N为5)个数从小到大排序后输出。
**输入格式要求:"%d" 提示信息:"Enter No.%2d:"
**输出格式要求:"%d"
程序运行示例如下:
Enter No. 1:5
Enter No. 2:7
Enter No. 3:3
Enter No. 4:9
Enter No. 5:8
35789
解法1:冒泡排序法
main() { int s[N]={0},i,j,a; for(i=0;i<N;i++) { printf("Enter No.%2d:",i+1); scanf("%d",&s[i]); } for(j=0;j<N;j++) { for(i=0;i<N;i++) { if(s[i]>s[i+1]) { a=s[i]; s[i]=s[i+1]; s[i+1]=a; } } } for(i=0;i<N;i++) { printf("%d",s[i]); } }
几何表示:
解法2:选择排序法
#include<stdio.h> #define N 5 main() { int a[N]= {0},i,j,min,k; for(i=0; i<N; i++) { printf("Enter No.%2d:",i+1); scanf("%d",&a[i]); } for ( i = 0; i <N; i ++ ) { k = i; for ( j = i + 1; j < N; j ++) { if ( a[ k ] > a[ j ] ) k = j; } if(k!=i) { min = a[ i ]; a[ i ] = a[ k ]; a[ k ] = min; } } for(i=0; i<N; i++) { printf("%d\n",a[i]); } }
几何表示:
今天早上又刷了一早上的题
本周练习为啥还有18个???
我表示极大的纳闷。。。
难度较低的题已经被我刷光了,可能难题刷的比较慢吧。
仅存的慰藉是我已经刷到了1810分,今天加加油,看能不能全刷完上2000分(要求全部的18道题都做对),但我感觉压力山大!!!
向着2500分的目标迈进;
如果可能,争取刷到3000分,拿到3分的加分!
废话不多说了!上代码!!!
PART .1
1.用递归方法编程计算输出Fibonacci数列,同时打印出计算Fibonacci数列每一项时所需的递归调用次数。
**输入格式要求:"%d" 提示信息:"Input n:"
**输出格式要求:"Fib(%d)=%d, count=%d\n"
程序运行示例如下:
Input n:10
Fib(1)=1, count=1
Fib(2)=1, count=3
Fib(3)=2, count=5
Fib(4)=3, count=9
Fib(5)=5, count=15
Fib(6)=8, count=25
Fib(7)=13, count=41
Fib(8)=21, count=67
Fib(9)=34, count=109
Fib(10)=55, count=177
先上我的垃圾错误代码
#include<stdio.h> fib(a); extern int c=0; main() { printf("Input n:"); int n,i,c; scanf("%d",&n); fib(n); } fib(a) { c=0; if(a==1) { printf("Fib(%d)=%d, count=%d\n",a,1,1); return 1; } if(a==2) { printf("Fib(%d)=%d, count=%d\n",a,2,3); return 1; } else { c++; printf("Fib(%d)=%d, count=%d\n",a,fib(a-1)+fib(a-2),c); } }
其实这道题的计算原理都不难,很轻松的就想出来了。
难的地方就在与输出格式还有c的计算。(吐槽一下——格式真的好烦人)
懒得查答案了,反正金币一大堆,不如直接花10金币看答案
#include <stdio.h> long Fib(int a); int count; /*全局变量count用于累计递归函数被调用的次数,自动初始化为0*/ int main() { int n, i, x; printf("Input n:"); scanf("%d", &n); for (i = 1; i <= n; i++) { count = 0; /* 计算下一项Fibonacci数列时将计数器count清零 */ x = Fib(i); printf("Fib(%d)=%d, count=%d\n", i, x, count); } return 0; } /* 函数功能:用递归法计算Fibonacci数列中的第n项的值 */ long Fib(int n) { long f; count++; /* 累计递归函数被调用的次数,记录于全局变量count中 */ if (n == 0) f = 0; else if (n == 1) f = 1; else f = Fib(n - 1) + Fib(n - 2); return f; }
PART .2
编写函数在return 值的时候,笔者总是希望return 多个值。
然而C语言不允许;
询问Kai大佬后大佬说用Struct 然而小白还没学到结构体怎么办???
于是便想到了下面的一些方法(参考链接):
1.利用全局变量
分析:全局变量作为C语言的一个知识点,虽然我们都了解它的特点,但在实际教学过程中应用得并不是很多。由于全局变量的作用域是从定义变量开始直到程序结束,而对于编写有多个返回值的C语言函数,我们可以考虑把要返回的多个值定义成全局变量。当函数被调用时,全局变量被更改,我们再把更改后的全局变量值应用于主调函数中。函数被调用后被更改后的全局变量值即为函数的数个返回值。下面以一个实例演示该方法的应用。
实例1:编写函数求3个数中的最大值与最小值。
方法:把最大值、最小值分别定义成2个全局变量max、min,在用户自定义函数中把求出来的最大值与最小值分别赋给全局变量max、min。函数调用完毕后全局变量的max、min值即保存了函数要求返回的值。程序参考代码如下:
#include "stdio.h" #include "conio.h" int max,min;/*定义两个全局变量用于保存函数返回值*/ void max_min(int a,int b,int c) /*定义求最大最小值的函数*/ {max=min=a; /*初始化最大最小值*/ if(max if(max if(min>b)min=b; if(min>c)min=c; } main() {int x,y,z; printf(" 请输入3个整数:\n"); scanf("%d,%d,%d",&x,&y,&z); max_min(x,y,z) ;/*调用求最大值与最小值的函数*/ printf("三个数中的最大值为:%d;最小值为:%d",max,min);/*输出最大值与最小值*/ getch(); }
调试结果如下:
请输入3个整数: 5,-6,2 三个数中的最大值为:5;最小值为:-6
注意:该方法虽然可以实现有多个返回值的函数,但由于全局变量不能保证值的正确性(因为其作用域是全局,所以程序范围内都可以修改它的值,如果出现错误将非常难以发现),并且全局变量增加了程序间模块的耦合,所以该方法要慎用。
2.传递数组指针
分析:在教学过程中,我们知道C语言函数参数的传递方式有值传递与地址传递。当进行值传递时,主调函数把实参的值复制给形参,形参获得从主调函数传递过来的值运行函数。在值传递过程中被调函数参数值的更改不能导致实参值的更改。而如果是地址传递,由于传递过程中从实参传递过来的是地址,所以被调函数中形参值的更改会直接导致实参值的更改。因此,我们可以考虑把多个返回值作为数组元素定义成一个数组的形式,并使该数组的地址作为函数的形式参数,以传址方式传递数组参数。函数被调用后,形参数组元素改变导致实参改变,我们再从改变后的实参数组元素中获得函数的多个返回值。以下实例演示该方法的应用。
实例2:编写函数求一维整形数组的最大值与最小值,并把最大值与最小值返回给主调函数。
方法:以指针方式传递该一维数组的地址,然后把数组的最大值与数组的第一个元素交换,把数组的最小值与最后一个元素交换。函数被调用完毕后,实参数组中的第一元素为数组的最大值,实参数组中最后一个元素为数组的最小值,从而实现返回数组的最大值与最小值的功能。程序参考代码如下:
#include "stdio.h" #include "conio.h" void max_min(int *ptr,int n) /*定义求数组最大值最小值的函数,传递数组指针*/ {int i,j,k;/*j保存最大值所在位置,k保存最小值所在位置*/ int *temp;/*用于交换位置*/ *temp=*ptr; for(i=0;i { if(*ptr<*(ptr+i))/*最大值与第一个元素进行交换*/ { k=i; *temp=*ptr; *ptr=*(ptr+k); *(ptr+k)=*temp ; } if(*(ptr+n-1)>*(ptr+i))/*最小值与最后一个元素进行交换*/ { j=i; *temp =*(ptr+n-1); *(ptr+n-1)=*(ptr+j); *(ptr+j)= *temp ;} } } /*调用最大最小值函数*/ main() { int A[6],i; for(i=0;i<6;i++) scanf("%d",&A[i]); max_min(A,6); printf("max=%d, min=%d\n \n",A[0],A[5]); getch(); }
调试结果如下:
请输入6个整形数,以空格隔开:
5 8 9 32 -6 4
max=32,min=-6
注意:该方法适用于多个返回值的数据类型一致的情况。当返回值数据类型不一致时,不适用该方法。
3.传递结构体指针
分析:结构体作为教学中的一个难点,教材对它介绍的内容并不多,应用的实例更是少之又少,所以学生对于结构体普遍掌握情况不理想。其实,编写返回多个值的C语言函数,也可以考虑采用结构体的方式去实现。通过方法2,我们知道如果返回的数个数值的数据类型不一致,可以通过定义全局变量实现有多个返回值的C语言函数,也可以考虑把要求返回的数个值定义成一个结构体,然后同样以传递结构体指针方式把结构体的指针传递给形参结构体指针,那么函数中对形参结构体的修改即是对实参结构体的修改,函数被调用后获取的实参结构体成员即为函数的多个返回值,下面以实例演示该方法的应用。
实例3:编写一个用户自定义函数,允许用户录入学生的基本信息(包括学号、姓名、所属班级、总评成绩),并返回这些基本信息给主调函数。
方法:把学生基本信息定义成一个结构体,在用户自定义函数中传递该结构体的指针,则自定义函数中对结构体成员的录入操作即是对实参结构体成员的录入操作,从而实现多个返回值。参考代码如下:
#include "stdio.h" #include "conio.h" struct inf{/*定义学生结构体,分别包含成员学号、姓名、班别、总评成绩*/ char xh[12]; char name[20]; char class[15]; int chj; }; main(void) { struct inf a1; /*定义学生结构体类型变量*/ void xxxx(struct inf *ptr); printf("请输入学号,姓名,班别,总评成绩,以空格隔开:\n") ; xxxx(&a1);/*调用函数,以学生结构体类型变量地址作为实参*/ printf("学号:%s,姓名: %s,班别:%s,总评成绩:%d",a1.xh, a1.name,a1.class,a1.chj); getch(); } void xxxx(struct inf *ptr)/*该函数实现对结构体成员数据的录入操作*/ { char xh1[12],name1[20],class1[15]; int chj1; scanf("%s%s%s%d",xh1,name1,class1,&chj1); strcpy(ptr->xh,xh1); strcpy(ptr->name,name1); strcpy(ptr->class,class1); ptr->chj=chj1; }
调试结果如下:
请输入学号,姓名,班别,总评成绩,以空格隔开:
200102LiLi200185
学号:200102,姓名: LiLi,班别:2001,总评成绩:85
注意:当函数要求返回的多个值是相互联系的或者返回的多个值数据类型不一致时可以采用该方法。
4.结束语
对于以上这三种方法,如果想要返回的数个值数据类型一致,可以考虑采用方法2;而对于不同数据类型的返回值,如果各个数值之间是相互联系的,则方法3较为合适;方法1虽然在很多情况下都可以实现多个返回值的C语言函数,但毕竟全局变量应用过程中有很多危险,要慎重使用。
通过对以上几种方法的分析讲解,在教学过程中,学生再遇到这样的问题时,就能根据返回值的情况选择合适的途径去实现多个返回值的C语言函数。另外,如果再遇到类似的无法用教材知识点去直接解决的问题时,他们基本都能举一反三地尝试采用间接方式去解决。
八月 | ||||||
---|---|---|---|---|---|---|
日 | 一 | 二 | 三 | 四 | 五 | 六 |
28 | 29 | 30 | 31 | 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |