多叉路口交通灯问题,输入任意道口数输出排序解决方案

多岔道口问题原理不想细解释,之前看到个大佬的详细解答很好先放上他的链接(我在一般的要求上增加了个特殊功能,使道路口和单向路不局限于5个)

​​​​​​(15条消息) 数据结构课设:多叉路口交通灯管理问题_此心安处是吾乡^_^的博客-CSDN博客

前置内容:动态二维数组要先申请指针的一维数组,再为指针new一个数组。

我这边主要讲一下新增内容的设计思路:

  首先使如果有n个路口,它们之间的联通关系(如从A到B)构成了n^2个节点(这里包含从A到A这样的,会在之后删去),我们会发现一件事,如果将这些节点依次排序,它们的序号w和出入路口间(m,k)的关系是这样的:w=n*(m-1)+k,据此我们就能得节点次序和实际意义的关系,并借此推算两个节点之间是否能同时通行。

ps:上述公式有个bug不知大家发现没有,就是k=n时,如果用除和取余得到实际意义会出错,所以在通过次序推出实际意义时要加一个检测函数

  然后呢我们来看如何判断从m道口到道口n的“指挥”和从i到k的“指挥”是否相冲突:

 两个通行路线相冲突也就代表着它俩的路线相交,而车辆的行驶路线又是两个道口之间越近,它们的凹凸度就越小(也就是说路线与路线之间都是尽可能相互躲避的不会出现图中情况)

 

  1. 我们给每一个道路口设置两个点,chu和ru,顾名思义,chu就是指这个点是车辆道口出去的位置,ru是车辆进入这一道口的位置,并依次标号1,2,3...,2*w

  2. 在这种“避让”条件下两条路线相交,实质上就是它们的直线段要相交(如下图),也就是说我们只需要看两条直线段的出入点是否相对(就是出现图中的情况,一个线段之间的之间的联系被另一边“截断”)

因此,我们判断相应的邻接矩阵的某点是1还是0的方法就转化为了判断这样的两种路线出入点间是否冲突的问题了(如下面的代码,这里将一些不需要的点置为2,方便填充邻接矩阵)(还顺手将部分不包含的通行方式关掉,方便之后应用)

int qidian1 = -1, zhongdian1 = -1,qidian2=-1,zhongdian2=-1,max1=-1,max2=-1,min1=-1,min2=-1;
	for (int i=0;i<w;i++)
	{
		//n*(h-1)+m=k+1  第h个路口向第m个跑
		if (((i+1)/n+1 )==((i+1)%n) || (i + 1) == w)//检测是否是自己向自己跑的情况,若是,则将fangshi中相应节点qiyong置为false并将相应矩阵置0
		{
			a[i].qiyong = false;
			for (int k = 0;k < w;k++)
			{
				chujvzhen[i][k] = 2;
			}
			continue;
		}
		//n*(h-1)+m=i+1  第h个路口向第m个跑,并在之后转化为图形中线段是否相交的问题(可能要在实验报告中解释,画不出图)
		qidian1 = (i + 1) / n + 1;
		zhongdian1 = (i + 1) % n;
		if (zhongdian1 == 0)
		{
			qidian1 =(qidian1-1)*2 - 1;
			zhongdian1=n;
			zhongdian1 = zhongdian1 * 2;
		}
		else
		{
			qidian1 = qidian1 * 2 - 1;
			zhongdian1 = zhongdian1 * 2 ;
		}
		max1 = qidian1 > zhongdian1 ? qidian1 : zhongdian1;
		min1= qidian1 < zhongdian1 ? qidian1 : zhongdian1;
		for (int k = 0;k < w;k++)
		{
			if (((k + 1) / n + 1) == ((k + 1) % n )||(k+1)==w)//检测是否是自己向自己跑的情况,防止意外产生(把矩阵值设为2)
			{
				chujvzhen[i][k] = 2;
				continue;
			}
			qidian2 = (k + 1) / n + 1;
			zhongdian2 = (k + 1) % n;
			if (zhongdian2 == 0)
			{
				qidian2 = (qidian2 - 1) * 2 - 1;
				zhongdian2 = n;
				zhongdian2 = zhongdian2 * 2;
			}
			else
			{
				qidian2 = qidian2 * 2 - 1;
				zhongdian2 = zhongdian2 * 2;
			}
			max2 = qidian2 > zhongdian2 ? qidian2 : zhongdian2;
			min2 = qidian2 < zhongdian2 ? qidian2 : zhongdian2;
			if (((min2 < min1)  && ((max2 < max1) && (max2 > min1))) || ((max2 > max1) && ((min2 > min1) && (min2 < max1))))
			{
				chujvzhen[i][k] = 1;
			}
			else 
			{
				chujvzhen[i][k] = 0;
			}
		}
	}

 这样我们就得到了一个初步的矩阵,之后就是对它删删改改进行修补(其实就是根据只入不出和只出不入”删掉“部分行/列,并关闭节点)

//将只入不出和只出不入的找出来,相应道口变成2;记录消去了多少行/列
	for (int i = 0;b[i] != 0;i++)
	{
		for (int k = 0;k < n;k++)
		{
			int xiao = k * n + b[i]-1;
			a[xiao].qiyong = false;
			for (int h = 0;h < w;h++)
			{
				chujvzhen[xiao][h] = 2;
				chujvzhen[h][xiao] = 2;
			}
		}
	}
	for (int i = 0;c[i] != 0;i++)
	{
		for (int k = 0;k < n;k++)
		{
			int xiao =(c[i]-1)*n+k;
			a[xiao].qiyong = false;
			for (int h = 0;h < w;h++)
			{
				chujvzhen[xiao][h] = 2;
				chujvzhen[h][xiao] = 2;
			}
		}
	}
	shanchu(a, w);
	

这样的话我们就已经得到了一个零阶矩阵的模型(尽管里面还有些值为2的“被删除点”)

接下来我们就能正式制作邻接矩阵了!

检测矩阵相应位点的值是否为2,为2则跳过,不为2则录入,并依据值是否为1为相应的点增加频度

int s = 0, t = 0;
 	int oo = (n * n - (rushu + chushu) * (n - 1) + rushu * chushu - n);
	//进行检测,0/1录入,2跳过
	for (int i = 0;i < w;i++)
	{
		for (int k = 0;k < w;k++)
		{
			if (chujvzhen[i][k] == 2)
			{
				continue;

			}
			else
			{
				d[s][t] = chujvzhen[i][k];
				if (chujvzhen[i][k] == 1)
				{
					a[s].pindu++;
					a[t].pindu++;
				}
				t++;
				if (t == oo)
				{
					s++;
					t = 0;
					continue;
				}
			}
		}
	}

 这样我们的邻接矩阵和节点的内容就基本制作内容就完成了,可以根据课本/大佬给出的方法规划道路了(下附完整代码)

本人能力有限,还懒,有些可以优化的地方没有改,大家要是有意见直接说就成

#include<iostream>
#include<cmath>
#include<queue>
using namespace std;
struct fangshi {
	int ru;
	int chu;//尽管能通过数组的次序来计算,但为了方便使用和后续排序问题用了churu
	int cixv;//方便在涂色中进行初始化(
	int pindu=0;//方便排序
	int color=0;
	bool qiyong=true;
};//记录出入的方式以及冲突数




void shanchu(fangshi *a,int n)//删除道路节点中不需要的项
{
 	int mount=n-1;
	for (int i = 0,k=0;k< n;k++)
	{
		if (a[i].qiyong == false&&a[i].ru!=0)
		{
			for (int k = i;k < n-1;k++)
			{
				a[k] = a[k + 1];
			}
			a[mount].pindu = 0;
			a[mount--].ru = 0;
		}
		if (a[i].qiyong != false)
		{
			i++;
		}
	}
	for (int i = 0;i < n;i++)
	{
		a[i].cixv = i;
	}
}




void zhizuoshuzu(int n, int b[]/*只能出*/, int c[]/*只能入*/, int**d,fangshi*a,int rushu,int chushu)//将输入的数据转化为临界矩阵方便后续进行计算
{
	int w = n*n;//计算有多少个通行方式(默认无单项情况,且包含从A向A的情况,这些问题都将在后续部分删除)
	int** chujvzhen = new int* [w];
	for (int i = 0; i < w; i++) {
		chujvzhen[i] = new int[w];
		a[i].ru = (i + 1) / n + 1;
		a[i].chu = (i + 1) % n;
		if ((i + 1) % n == 0)
		{
			a[i].ru--;
			a[i].chu=n;
		}
		a[i].cixv = i;
	}//创建一个关于某两种通行方式是否可以同时开始的邻接矩阵,并将通行方式的节点初始化
	
	int qidian1 = -1, zhongdian1 = -1,qidian2=-1,zhongdian2=-1,max1=-1,max2=-1,min1=-1,min2=-1;
	for (int i=0;i<w;i++)
	{
		//n*(h-1)+m=k+1  第h个路口向第m个跑
		if (((i+1)/n+1 )==((i+1)%n) || (i + 1) == w)//检测是否是自己向自己跑的情况,若是,则将fangshi中相应节点qiyong置为false并将相应矩阵置0
		{
			a[i].qiyong = false;
			for (int k = 0;k < w;k++)
			{
				chujvzhen[i][k] = 2;
			}
			continue;
		}
		//n*(h-1)+m=i+1  第h个路口向第m个跑,并在之后转化为图形中线段是否相交的问题(可能要在实验报告中解释,画不出图)
		qidian1 = (i + 1) / n + 1;
		zhongdian1 = (i + 1) % n;
		if (zhongdian1 == 0)
		{
			qidian1 =(qidian1-1)*2 - 1;
			zhongdian1=n;
			zhongdian1 = zhongdian1 * 2;
		}
		else
		{
			qidian1 = qidian1 * 2 - 1;
			zhongdian1 = zhongdian1 * 2 ;
		}
		max1 = qidian1 > zhongdian1 ? qidian1 : zhongdian1;
		min1= qidian1 < zhongdian1 ? qidian1 : zhongdian1;
		for (int k = 0;k < w;k++)
		{
			if (((k + 1) / n + 1) == ((k + 1) % n )||(k+1)==w)//检测是否是自己向自己跑的情况,防止意外产生(把矩阵值设为2)
			{
				chujvzhen[i][k] = 2;
				continue;
			}
			qidian2 = (k + 1) / n + 1;
			zhongdian2 = (k + 1) % n;
			if (zhongdian2 == 0)
			{
				qidian2 = (qidian2 - 1) * 2 - 1;
				zhongdian2 = n;
				zhongdian2 = zhongdian2 * 2;
			}
			else
			{
				qidian2 = qidian2 * 2 - 1;
				zhongdian2 = zhongdian2 * 2;
			}
			max2 = qidian2 > zhongdian2 ? qidian2 : zhongdian2;
			min2 = qidian2 < zhongdian2 ? qidian2 : zhongdian2;
			if (((min2 < min1)  && ((max2 < max1) && (max2 > min1))) || ((max2 > max1) && ((min2 > min1) && (min2 < max1))))
			{
				chujvzhen[i][k] = 1;
			}
			else 
			{
				chujvzhen[i][k] = 0;
			}
		}
	}
	//将只入不出和只出不入的找出来,相应道口变成2;记录消去了多少行/列
	for (int i = 0;b[i] != 0;i++)
	{
		for (int k = 0;k < n;k++)
		{
			int xiao = k * n + b[i]-1;
			a[xiao].qiyong = false;
			for (int h = 0;h < w;h++)
			{
				chujvzhen[xiao][h] = 2;
				chujvzhen[h][xiao] = 2;
			}
		}
	}
	for (int i = 0;c[i] != 0;i++)
	{
		for (int k = 0;k < n;k++)
		{
			int xiao =(c[i]-1)*n+k;
			a[xiao].qiyong = false;
			for (int h = 0;h < w;h++)
			{
				chujvzhen[xiao][h] = 2;
				chujvzhen[h][xiao] = 2;
			}
		}
	}
	shanchu(a, w);
	
	int s = 0, t = 0;
 	int oo = (n * n - (rushu + chushu) * (n - 1) + rushu * chushu - n);
	//进行检测,0/1录入,2跳过
	for (int i = 0;i < w;i++)
	{
		for (int k = 0;k < w;k++)
		{
			if (chujvzhen[i][k] == 2)
			{
				continue;

			}
			else
			{
				d[s][t] = chujvzhen[i][k];
				if (chujvzhen[i][k] == 1)
				{
					a[s].pindu++;
					a[t].pindu++;
				}
				t++;
				if (t == oo)
				{
					s++;
					t = 0;
					continue;
				}
			}
		}
	}
	for(int i = 0;i < oo;i++)
	{
		d[i][i] = 1;
		a[i].pindu++;
	}
	
 	for (int i = 0; i < w; i++)
	{
		delete[]chujvzhen[i];
		chujvzhen[i] = NULL;
	}
	delete[]chujvzhen;
	chujvzhen = NULL;
}



void maopaopaixv(fangshi*a,int n)//冒泡排序
{
	for (int i = 0;i < n;i++) {
		for (int j = n-1;j > i;j--) {
			if (a[j].pindu > a[j - 1].pindu) {
				int degree = a[j - 1].pindu;
				int index = a[j - 1].cixv;
				int ru=a[j-1].ru,
					chu=a[j-1].chu;
				bool	qiyong=a[j-1].qiyong;
				a[j - 1].pindu = a[j].pindu;
				a[j - 1].cixv = a[j].cixv;
				a[j - 1].ru = a[j].ru;
				a[j - 1].chu = a[j].chu;
				a[j - 1].qiyong = a[j].qiyong;
				a[j].pindu = degree;
				a[j].cixv = index;
				a[j].ru = ru;
				a[j].chu = chu;
				a[j].qiyong = qiyong;
			}

		}
	}
}

bool shangse(fangshi *a, int** d, int color, int j,int n) //检测j能否上color的“颜色”
{
	if (a[j].color != 0)
		return false;
	for (int i = 0;i < n&&a[i].ru!=0;i++)
		if (d[a[j].cixv][i] == 1)
		{
			for (int m = 0;m < n && a[m].ru != 0;m++)
			{
				if (a[m].cixv == i)
				{
					if (a[m].color == color)
					{
						return false;
					}
				}
			}
		}
	return true;
}


int main()
{
	int h,** d=NULL,chushu=0,rushu=0;
	cout << "输入道路数" << endl;
	cin >> h;
	int* b = new int[h];
	int* c = new int[h];
	cout << "输入只能出的路口数,输入0截止" << endl;
	int n = 0;
	do
	{
		cin >> n;
		b[chushu] = n;
		if(n !=0)
		chushu++;
	} while (n != 0);
	cout << "输入只能入的路口数,输入0截止" << endl;
	do
	{
		cin >> n;
		c[rushu] = n;
		if (n != 0)
			rushu++;
	} while (n != 0);
	int zeze = h * h - (rushu + chushu) * (h - 1)+rushu*chushu - h;
	d = new int* [zeze];
	for (int i = 0; i <zeze; i++) {
		d[i] = new int[zeze]();
	}
 	fangshi* daolu = new fangshi[h*h];
	zhizuoshuzu(h, b, c, d,daolu,rushu,chushu);
	maopaopaixv(daolu, h * h);
	int k = 0;
	while (1) 
	{
		k++;
		int i;
		for (i = 0;i < h*h&&daolu[i].ru!=0;i++)
			if (daolu[i].color == 0) 
			{
				daolu[i].color = k;
				break;
			}

		if (i == h*h||daolu[i].ru==0)
			break;

		for (int j = 0;j < h * h && daolu[j].ru != 0;j++)
			if (shangse(daolu, d, k, j, h * h))
			{
				daolu[j].color = k;
			}
	}
	
	cout << "一下是一种满足要求(“涂色最少”)的交通灯考虑,一次完整的行驶共有" <<--k<< "段行驶(颜色),具体情况如下:" << endl;
	for (int i=1;k> 0;k--)
	{
		cout << "第" << i++ << "段行驶:";
		for (int o = 0;(o < h * h) && (daolu[o].ru != 0);o++)
		{
			if (daolu[o].color == k)
			{
				cout << "从第" << daolu[o].ru << "路口向第" << daolu[o].chu << "路口 ";
			}
		}
		cout << endl;
	}

	delete[]b;
	b = NULL;
	delete[]c;
	c = NULL;
	delete[]d;
	d = NULL;
	delete[] daolu;
	daolu = NULL;
	return 0;
}

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值