《C系列-实例相关》C语言实例一

C语言实例一

1.基于C语言TSP算法问题

TSP问题求解:
1.利用 CreateMat()函数调用主函数中的数组,并创建邻接矩阵,通过 DispMat()输出矩阵。
2.整个问题的求解建立在邻接矩阵的基础上。
3.TSP()是主要的算法步骤,在TSP() 中实现了最短路径长度以及最短路径的输出。
4.getpathlen()函数可以获取apath的长度,Enumerate()用来获取最短路径,被TSP()函数调用。

#include<stdio.h>
#define INF 32767
#define MAXV 20
#define MAXL 20
int minpath[MAXV];//保存最短路径 
int minpathlen = INF;//保存最短路径长度 
typedef struct
{	int no;						//顶点编号
	char data[MAXL];			//顶点其他信息
} VertexType;					//顶点类型
typedef struct
{	int edges[MAXV][MAXV];		//邻接矩阵的边数组
	int n,e;					//顶点数,边数
	VertexType vexs[MAXV];		//存放顶点信息
} MGraph;						//完整的图邻接矩阵类型
void CreateMat(MGraph &g,int A[][MAXV],int n,int e)	//建立图的邻接矩阵
{	int i,j;
	g.n=n; g.e=e;
	for (i=0;i<n;i++)
		for (j=0;j<n;j++)
			g.edges[i][j]=A[i][j];
}
void DispMat(MGraph g)			//输出图的邻接矩阵
{	int i,j;
	printf("  n=%d,e=%d\n",g.n,g.e);
	for (i=0;i<g.n;i++)
	{	for (j=0;j<g.n;j++)
			if (g.edges[i][j]==INF)
				printf("%4s","∞");
			else
				printf("%4d",g.edges[i][j]);
		printf("\n");
	}
}
int getpathlen(MGraph g,int apath[])//求apath中保存路径的路径长度 
{
	int i;
	int sum = g.edges[0][apath[0]];//先求从0到第一个点的距离 
	for(i=1;i<g.n-1;i++)
		sum+=g.edges[apath[i-1]][apath[i]];
	sum+=g.edges[apath[i-1]][0];//加上最后一个点到0点的距离 
	return sum;
 } 
 void Enumerate(MGraph g,int apath[],int i)//利用穷举法求解最短路径 
 {
 	int k,j,tmp;
 	if(i==g.n-2)//当apath中包含所有中间顶点时 
 	{
 		if(g.edges[i][0]!=0&&g.edges[i][0]!=INF)//找到一条回路 
 		{
 			if(minpathlen>getpathlen(g,apath))//路径长度比较 
 			{
 				minpathlen=getpathlen(g,apath);//保存最短路径长度 
 				for(j=0;j<g.n-1;j++)//保存最短路径 
 					minpath[j]=apath[j];
			 }
		 }
	 }
	 else//当apath中没有所有中间顶点的时候 
	 {
	 	for(k=i;k<g.n-1;k++)//找从顶点i出发的所有路径 
	 	{
	 		tmp=apath[i];//顶点apath[i]和apath[k]交换 
	 		apath[i]=apath[k];
			 apath[k]=tmp;
	 		Enumerate(g,apath,i+1);//从顶点apath[i+1]开始搜索 
	 		tmp=apath[i];//顶点apath[k]和apath[i]交换 
	 		apath[i]=apath[k];apath[k]=tmp;
		 }
	 }
 }
 void TSP(MGraph g)//用穷举法求解TSP问题 
 {
 	int i;
 	int apath[MAXV];//apath存放从起点0到起点0的回路的中间顶点 
 	for(i=1;i<g.n;i++)//将顶点1-3放入apath作为初始路径 
 		apath[i-1]=i;
 	minpathlen=getpathlen(g,apath);//初始化路径长度 
 	Enumerate(g,apath,0);//把路径以及路径长度打印出来 
 	printf("最短路径长度=%d\n",minpathlen);
 	printf("最短路径:");
 	printf("0->");
 	for(i=0;i<g.n-1;i++)//输出最短路径 
 		printf("%d->",minpath[i]);
 	printf("%d\n",0);
 }
int main()
{
	MGraph g;
	int A[][MAXV]={
					{0,8,5,36},
					{6,0,8,5},
					{8,9,0,5},
					{7,7,8,0},
					};
	int n=4,e=12;
	CreateMat(g,A,n,e);//创建邻接矩阵 
	printf("图的邻接矩阵"); 
	DispMat(g);//输出邻接矩阵 
	printf("TSP问题结果\n");
	TSP(g); //调用prim算法 
}

2.生产者与消费者

#include <stdio.h>
#include <pthread.h>
#include <windows.h>
#define N 100
#define true 1
#define producerNum  10
#define consumerNum  5
#define sleepTime 1000

typedef int semaphore;
typedef int item;
item buffer[N] = {0};
int in = 0;
int out = 0;
int proCount = 0;
semaphore mutex = 1, empty = N, full = 0, proCmutex = 1;

void * producer(void * a){
    while(true){
        while(proCmutex <= 0);
        proCmutex--;
        proCount++;
        printf("生产一个产品ID%d, 缓冲区位置为%d\n",proCount,in);
        proCmutex++;

        while(empty <= 0){
            printf("缓冲区已满!\n");
        }
        empty--;

        while(mutex <= 0);
        mutex--;

        buffer[in] = proCount;
        in = (in + 1) % N;

        mutex++;
        full++;
        Sleep(sleepTime);
    }
}

void * consumer(void *b){
    while(true){
        while(full <= 0){
            printf("缓冲区为空!\n");
        }
        full--;

        while(mutex <= 0);
        mutex--;

        int nextc = buffer[out];
        buffer[out] = 0;//消费完将缓冲区设置为0

        out = (out + 1) % N;

        mutex++;
        empty++;

        printf("\t\t\t\t消费一个产品ID%d,缓冲区位置为%d\n", nextc,out);
        Sleep(sleepTime);
    }
}

int main()
{
    pthread_t threadPool[producerNum+consumerNum];
    int i;
    for(i = 0; i < producerNum; i++){
        pthread_t temp;
        if(pthread_create(&temp, NULL, producer, NULL) == -1){
            printf("ERROR, fail to create producer%d\n", i);
            exit(1);
        }
        threadPool[i] = temp;
    }//创建生产者进程放入线程池


    for(i = 0; i < consumerNum; i++){
        pthread_t temp;
        if(pthread_create(&temp, NULL, consumer, NULL) == -1){
            printf("ERROR, fail to create consumer%d\n", i);
            exit(1);
        }
        threadPool[i+producerNum] = temp;
    }//创建消费者进程放入线程池


    void * result;
    for(i = 0; i < producerNum+consumerNum; i++){
        if(pthread_join(threadPool[i], &result) == -1){
            printf("fail to recollect\n");
            exit(1);
        }
    }//运行线程池
    return 0;
}

3.不重复三位数

题目:有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?

1.程序分析:
可填在百位、十位、个位的数字都是1、2、3、4。组成所有的排列后再去掉不满足条件的排列。
2.程序源代码:

main()
{
int i,j,k;
printf("\n");
for(i=1;i<5;i++)    /*以下为三重循环*/
 for(j=1;j<5;j++) 
  for (k=1;k<5;k++)
   {
    if (i!=k&&i!=j&&j!=k)    /*确保i、j、k三位互不相同*/
    printf("%d,%d,%d\n",i,j,k);
   }
}

4.利润计算

题目:

企业发放的奖金根据利润提成。利润(I)低于或等于10万元时,奖金可提10%;利润高于10万元,低于20万元,
低于10万元的部分按10%提成,高于10万元的部分,可可提成7.5%;20万到40万之间时,高于20万元的部分,
可提成5%;40万到60万之间时高于40万元的部分,可提成3%;60万到100万之间时,高于60万元的部分,
可提成1.5%,高于100万元时,超过100万元的部分按1%提成,从键盘输入当月利润I,求应发放奖金总数?

1.程序分析:

请利用数轴来分界,定位。注意定义时需把奖金定义成长整型。

2.程序源代码:

main()
{
long int i;
int bonus1,bonus2,bonus4,bonus6,bonus10,bonus;
scanf("%ld",&i);
bonus1=100000*0.1;bonus2=bonus1+100000*0.75;
bonus4=bonus2+200000*0.5;
bonus6=bonus4+200000*0.3;
bonus10=bonus6+400000*0.15;
 if(i<=100000)
  bonus=i*0.1;
 else if(i<=200000)
     bonus=bonus1+(i-100000)*0.075;
    else if(i<=400000)
        bonus=bonus2+(i-200000)*0.05;
       else if(i<=600000)
           bonus=bonus4+(i-400000)*0.03;
          else if(i<=1000000)
              bonus=bonus6+(i-600000)*0.015;
             else
              bonus=bonus10+(i-1000000)*0.01;
printf("bonus=%d",bonus);
} 

5.完全平方数

题目:

一个整数,它加上100后是一个完全平方数,再加上168又是一个完全平方数,请问该数是多少?

1.程序分析:

在10万以内判断,先将该数加上100后再开方,再将该数加上268后再开方,如果开方后

的结果满足如下条件,即是结果。请看具体分析:

2.程序源代码:

#include "math.h"
main()
{
long int i,x,y,z;
for (i=1;i<100000;i++)
 { x=sqrt(i+100);   /*x为加上100后开方后的结果*/
  y=sqrt(i+268);   /*y为再加上168后开方后的结果*/
   if(x*x==i+100&&y*y==i+268)/*如果一个数的平方根的平方等于该数,这说明此数是完全平方数*/
    printf("\n%ld\n",i);
 }
}

6.天次判断

题目:

输入某年某月某日,判断这一天是这一年的第几天?

1.程序分析:

以3月5日为例,应该先把前两个月的加起来,然后再加上5天即本年的第几天,特殊情况,闰年且输入

月份大于3时需考虑多加一天。

2.程序源代码:

main()
{
int day,month,year,sum,leap;
printf("\nplease input year,month,day\n");
scanf("%d,%d,%d",&year,&month,&day);
switch(month)/*先计算某月以前月份的总天数*/
{
 case 1:sum=0;break;
 case 2:sum=31;break;
 case 3:sum=59;break;
 case 4:sum=90;break;
 case 5:sum=120;break;
 case 6:sum=151;break;
 case 7:sum=181;break;
 case 8:sum=212;break;
 case 9:sum=243;break;
 case 10:sum=273;break;
 case 11:sum=304;break;
 case 12:sum=334;break;
 default:printf("data error");break;
}
sum=sum+day;  /*再加上某天的天数*/
 if(year%400==0||(year%4==0&&year%100!=0))/*判断是不是闰年*/
  leap=1;
 else
  leap=0;
if(leap==1&&month>2)/*如果是闰年且月份大于2,总天数应该加一天*/
sum++;
printf("It is the %dth day.",sum);}

7.交换输出法

题目:

输入三个整数x,y,z,请把这三个数由小到大输出。

1.程序分析:

我们想办法把最小的数放到x上,先将x与y进行比较,如果x>y则将x与y的值进行交换,
然后再用x与z进行比较,如果x>z则将x与z的值进行交换,这样能使x最小。

2.程序源代码:

main()
{
int x,y,z,t;
scanf("%d%d%d",&x,&y,&z);
if (x>y)
{t=x;x=y;y=t;} /*交换x,y的值*/
if(x>z)
{t=z;z=x;x=t;}/*交换x,z的值*/
if(y>z)
{t=y;y=z;z=t;}/*交换z,y的值*/
printf("small to big: %d %d %d\n",x,y,z);
}

8.基于C语言的广度优先算法

#include"./Graph.cpp" 	
void BFS(MGraph g,int v)
{
	int qu[MAXV],front=0,rear=0;//定义循环队列并初始化 
	int visited[MAXV];//定义存放节点的访问标志的数组 
	int w,i;
	for(i=0;i<g.n;i++)//访问标志数组初始化 
	visited[i]=0;//输出被访问顶点的编号 
	printf("%3d",v);//置已访问标记 
	visited[v]=1;
	rear=(rear+1)%MAXV;//V进队 
	qu[rear]=v;//若队列不空时循环 
	while(front!=rear)
	{
		front=(front+1)%MAXV;
		w=qu[front];//出队并赋给V 
		for(i=0;i<g.n;i++)//找与W相邻的顶点 
			if(g.edges[w][i]!=0 && g.edges[w][i]!=INF && visited[i]==0)
			{//若当前邻接顶点i未被访问 
				printf("%3d",i);//访问相邻顶点 
				visited[i]=1;//置该定点已被访问的标志 
				rear=(rear+1)%MAXV;//该顶点进队 
				qu[rear]=i;
			}
	}
	printf("\n");
}
int main()
{
	MGraph g;
	int A[][MAXV]={
					{INF,4,6,6,INF,INF,INF},
					{4,INF,1,INF,7,INF,INF},
					{6,1,INF,2,6,4,INF},
					{6,INF,2,INF,INF,1,6},
					{INF,7,6,INF,INF,1,6},
					{INF,INF,4,5,1,INF,8},
					{INF,INF,INF,INF,6,8,INF}
					};
	int n=7,e=12;
	CreateMat(g,A,n,e);//创建邻接矩阵 
	printf("图的邻接矩阵");
	DispMat(g);//输出邻接矩阵 
	printf("广度优先遍历\n");
	BFS(g,0);	
}	

9.基于C语言的深度优先遍历算法

#include"./Graph.cpp"
int visited[MAXV];
void DFS(MGraph g,int v)
{
	int w;	
	printf("%3d",v);//输出被访问顶点的编号 
	visited[v]=1;//置已访问标记 
	for(w=0;w<g.n;w++)//找定点V的所有相邻点 
		if(g.edges[v][w]!=0&&g.edges[v][w]!=INF&&visited[w]==0)
			DFS(g,w);//找顶点V味访问的相邻定点W 
}
int main()
{
	MGraph g;
	int A[][MAXV]={
					{INF,4,6,6,INF,INF,INF},
					{4,INF,1,INF,7,INF,INF},
					{6,1,INF,2,6,4,INF},
					{6,INF,2,INF,INF,1,6},
					{INF,7,6,INF,INF,1,6},
					{INF,INF,4,5,1,INF,8},
					{INF,INF,INF,INF,6,8,INF}
					};
	int n=7,e=12;
	CreateMat(g,A,n,e);//创建邻接矩阵 
	printf("图的邻接矩阵");
	DispMat(g);//输出邻接矩阵 
	printf("深度优先遍历\n");
	DFS(g,0);//调用深度优先遍历 
} 

10.基于C语言的克鲁斯卡尔算法

克鲁斯卡尔算法:
1.克鲁斯卡尔算法是一种按照权值的递增次序选择合适的边来构造最小生成树的方法。
2.G=(V,E)是一个具有n个顶点e条边的带权连通无向图,t=(e,te)是g的最小生成树。
3.通过并查集判断选取的边与树中已经保留的边是否冲突
4.n元素的分离集合树,其高度最高为log2n

#include<stdio.h>
#define INF 32767
#define MAXV 20
#define MAXL 20
int MaxSize = 100;//设置最大的容量 
typedef struct node
{
	int data;//节点对应顶点编号 
	int rank;//节点对应秩(深度) 
	int parent;//节点对应双亲下标 
}UFSTree;//并查集数的节点类型 
typedef struct
{
	int u;//边的起始顶点 
	int v;//边的终止节点 
	int w;//边的权值 
 } Edge;
typedef struct
{	int no;						//顶点编号
	char data[MAXL];			//顶点其他信息
} VertexType;					//顶点类型
typedef struct
{	int edges[MAXV][MAXV];		//邻接矩阵的边数组
	int n,e;					//顶点数,边数
	VertexType vexs[MAXV];		//存放顶点信息
} MGraph;						//完整的图邻接矩阵类型
void CreateMat(MGraph &g,int A[][MAXV],int n,int e)	//建立图的邻接矩阵
{	int i,j;
	g.n=n; g.e=e;
	for (i=0;i<n;i++)
		for (j=0;j<n;j++)
			g.edges[i][j]=A[i][j];
}
void DispMat(MGraph g)			//输出图的邻接矩阵
{	int i,j;
	printf("  n=%d,e=%d\n",g.n,g.e);
	for (i=0;i<g.n;i++)
	{	for (j=0;j<g.n;j++)
			if (g.edges[i][j]==INF)
				printf("%4s","∞");
			else
				printf("%4d",g.edges[i][j]);
		printf("\n");
	}
}
void MAKE_SET(UFSTree t[],int n)//初始化 
{
	int i;
	for(i=0;i<n;i++)//顶点编号为0-n-1 
	{
		t[i].rank=0;//秩(深度)初始化 
		t[i].parent=i;//双亲初始化指向自己 
	}
 } 
int FIND_SET(UFSTree t[],int x)//在x所在子树中查找编号 
 {
 	if(x!=t[x].parent)
 		return(FIND_SET(t,t[x].parent));
 	else
 		return(x);
 }
void UNION(UFSTree t[],int x,int y)//将x和y所在子树合并 
 {
 	x=FIND_SET(t,x);//查找编号 
 	y=FIND_SET(t,y);
 	if(t[x].rank>t[y].rank)//y节点的深度小于x节点的深度 
 		t[y].parent=x;//将y连接到x上,x作为y的节点
		  
 	else
 	{
 		t[x].parent=y;
 		if(t[x].rank==t[y].rank)
 			t[y].rank++;
	 }
 }
void sift(Edge R[],int low,int high)
{	int i=low,j=2*i;						//R[j]是R[i]的左孩子
	Edge tmp=R[i];
	while (j<=high)
	{	if (j<high && R[j].w<R[j+1].w) 	//若右孩子较大,把j指向右孩子
			j++;
		if (tmp.w<R[j].w) 
		{	R[i]=R[j];						//将R[j]调整到双亲节点位置上
			i=j;							//修改i和j值,以便继续向下筛选
			j=2*i;
		}
		else break;							//筛选结束
	}
	R[i]=tmp;								//被筛选节点的值放入最终位置
}
void HeapSort(Edge R[],int n)
{	int i;
	Edge tmp;
	for (i=n/2;i>=1;i--)	//循环建立初始堆
		sift(R,i,n); 
	for (i=n;i>=2;i--)		//进行n-1趟完成推排序,每一趟堆排序的元素个数减1
	{	tmp=R[1];			//将最后一个元素同当前区间内R[1]对换
		R[1]=R[i];
		R[i]=tmp;
		sift(R,1,i-1);		//筛选R[1]节点,得到i-1个节点的堆
	}
}
void Kruskal(MGraph g)
{	
	int i,j,k,u1,v1,sn1,sn2;
	UFSTree t[MaxSize];
	Edge E[MaxSize];
	k=0;//e数组的下标从0开始
	for(i=0;i<g.n;i++)//由g下三角部分产生的边集E
		for(j=0;j<i;j++)
			if(g.edges[i][j]!=0&&g.edges[i][j]!=INF)
			{
				E[k].u=i;E[k].v=j;E[k].w=g.edges[i][j];
				k++;
			}
	HeapSort(E,g.e);//采取堆排序对E数组按权值递增排序
	MAKE_SET(t,g.n);//初始化并查集t	
	k=1;//k表示当前构造树的第几条边,初值为1
	j=0;//E中边的下标,初值为0
	while(k<g.n)
	{
		u1=E[j].u;
		v1=E[j].v;//取一条边的头尾顶点编号U1和V1
		sn1=FIND_SET(t,u1);
		sn2=FIND_SET(t,v1);//分别得到两个顶点所属的集合编号
		if(sn1!=sn2)//添加该边不会构成回路,将该边作为最小生成树的一条边
		{
			printf("(%d,%d):%d\n",u1,v1,E[j].w);
			k++;//生成边数增1
			UNION(t,u1,v1);//扫描下一条边
		}
		j++;	
	}	
 } 
int main()
{
	MGraph g;
	int A[][MAXV]={
					{0,4,6,6,INF,INF,INF},
					{4,0,1,INF,7,INF,INF},
					{6,1,0,2,6,4,INF},
					{6,INF,2,0,INF,1,6},
					{INF,7,6,INF,0,1,6},
					{INF,INF,4,5,1,0,8},
					{INF,INF,INF,INF,6,8,0}
					};
	int n=7,e=12;
	CreateMat(g,A,n,e);//创建邻接矩阵 
	printf("图的邻接矩阵"); 
	DispMat(g);//输出邻接矩阵 
	printf("Kruskal算法结果\n");
	Kruskal(g); //调用prim算法 
}	



  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DATA数据猿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值