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