求一个图的最小顶点覆盖集Red,图用关联矩阵B表示,若删除掉集合Red中一个元素仍然能覆盖整个图,则可以通过删除该元素得到新的最简Red集。若不能,则保留原来的Red集。
例:图为B,原有的属性集为A=[1,2,3,4,5],但通过别的算法可以得到约简为Red=[1,2,3,4];现要对已求得的Red集再进行约简得到最小的约简集。
B=[0,1,0,0,0; (对应边e1)
0,0,1,0,0; (对应边e2)
0,1,1,0,0; (对应边e3)
1,0,0,1,0; (对应边e4)
1,0,0,0,1]; (对应边e5)
通过(最小约简)步骤后,应该得到更小的属性约简集为Red=[1,2,3].
设计代码
clear
clc
B=[0,1,0,0,0;0,0,1,0,0;0,1,1,0,0;1,0,0,1,0;1,0,0,0,1];
Red=[1,2,3,4];
[m,n]=size(B);
for k=1:length(Red(:))
a=Red;
a(k)=[];
clear A;
for i=1:m
[~,j]=find(B(i,:)>0); %找到第i行不为0的元素坐标
A=intersect(a,j);
if isempty(A) %若交集为空时,跳出循环
break
end
disp(a) %若对于B中从1-m行每行与Red交不为空,则输出新的Red集。(此处为难点)
end
end
以上代码实现不了,难点处设计应该有误,不知如何改正,能实现结果。
三、代码展示
min_ball.m(框架部分)
function min_ball
syms a b c;
ooo=[a b c];
o=[0 0 0]; %球心
R=0; %球的半径
n=input('请输入你想要生成的离散点个数:');
t=input('请输入你想要生成的点的范围(上限):');
A=rand(n,3);
B=(2A-1)t;
%随机产生n个离散点,储存在pot里面
pot=fix(B)+1;
%生成最小球
for i=1:n
if norm(pot(i,:)-o)>R
o = pot(i,:);
R=0;
for j=1:i-1
if norm(pot(j,:)-o)>R
o = (pot(i,:)+pot(j,:))/2;
R=norm(pot(j,:)-o);
for k=1:j-1
if norm(pot(k,:)-o)>R
%最小外接球(补充ball函数)
%ball函数输入三个点坐标,返回这三个点的最小球的球心坐标
x=pot(i,:);
y=pot(j,:);
z=pot(k,:);
if norm(z-y)^2+4R^2<=(norm(z-x))^2
ooo=(z+x)/2;
R=norm(z-ooo);
elseif norm(z-x)^2+4R^2<=(norm(z-y))^2
ooo=(z+y)/2;
R=norm(z-ooo);
else %三个点构成锐角三角形的情况
ooo=ballcenter(x,y,z);
R=norm(z-ooo);
o = ooo;
R=norm(pot(k,:)-o);
end
end
end
end
end
end
end
o=double(o); %保证小数防止mesh出bug
R=double(R);
[q, w, e]=sphere(30);
Q=Rq+o(1);
W=Rw+o(2);
E=R*e+o(3);
subplot(1,3,1)
mesh(Q,W,E)
hold on
%画n个点
x1=pot(:,1);
y1=pot(:,2);
z1=pot(:,3);
subplot(1,3,2)
scatter3(x1,y1,z1,'r');
hold on
subplot(1,3,3)
mesh(Q,W,E);
alpha(0.8) %设置透明度
shading flat %去掉那道些线
hold on
scatter3(x1,y1,z1,'r');
ballcenter.m(求最小球球心)
function p = ballcenter(x, y, z)
syms a b c;
% 圆的法向量
pf= cross(x-y, x-z);
p12 = (x + y)/2;
p23 = (y + z)/2;
% 求两条在三角形面内的中垂线的向量
p12f = cross(pf, x-y);
p23f = cross(pf, y-z);
eq1=(a-p12(1))*p12f(2)-(b-p12(2))*p12f(1);
eq2=(a-p12(1))*p12f(3)-(c-p12(3))*p12f(1);
eq3=(a-p23(1))*p23f(2)-(b-p23(2))*p23f(1);
eq4=(a-p23(1))*p23f(3)-(c-p23(3))*p23f(1);
[a,b,c]=solve(eq1,eq2,eq3,eq4,a,b,c);
p=[a b c];
end
四、结果展示
20个点,范围[-10,10]
30个点,范围[-20,20]
30个点,范围[-50,50]
40个点,范围[-100,100]
% 算法思路:
% 1. 在点集中任取3点A,B,C。
% 2. 作一个包含A,B,C三点的最小圆,圆周可能通过32313133353236313431303231363533e58685e5aeb931333264646533这3点,也可能只通过其中两点,但包含第3点.后一种情况圆周上的两点一定是位于圆的一条直径的两端。
% 3. 在点集中找出距离第2步所建圆圆心最远的D点,若D点已在圆内或圆周上,则该圆即为所求的圆,算法结束.否则执行第4步。
% 4. 在A,B,C,D中选3个点,使由它们生成的一个包含这4个点的圆为最小,这3 点成为新的A,B,C,返回执行第2步。
% 若在第4步生成的圆的圆周只通过A,B,C,D 中的两点,则圆周上的两点取成新的A和B,从另两点中任取一点作为新的C。
clear all;close all;clc;
x=[22 8 4 51 38 17 81 18 62]
y=[38 13 81 32 11 12 63 45 12]
plot(x,y,'*');hold on;
grid on%
set_3P=nchoosek(1:length(x),3);
AI=set_3P(1,1);
BI=set_3P(1,2);
CI=set_3P(1,3);
A=[x(AI) y(AI)];
B=[x(BI) y(BI)];
C=[x(CI) y(CI)];
while 1
R=minCirclePoints3(A,B,C);
cr=[R(1),R(2)];
r=zeros(1,length(x));
for i=1:length(x)
r(i)=sqrt((x(i)-cr(1))^2+(y(i)-cr(2))^2);
end;
maxValue=max(r); %或者N=max(r(:))
[mc]=find(maxValue==r);
if r(mc)<=R(3)%没有点在圆外,结束回家吃饭去
alpha=0:pi/20:2*pi;%角度[0,2*pi]
plot(cr(1)+R(3)*cos(alpha),cr(2)+R(3)*sin(alpha),'--r');%中心点在(R(1),R(2))半径为R(3)的圆
axis equal;
break;%所有点都被圆覆盖
else
%距离圆心最远的点在圆外
end;
D=[x(mc),y(mc)];
P=[A;B;C;D];%保存这四个点的坐标
DI=mc;
set_3P=nchoosek([AI,BI,CI,DI],3);
rSet=[];
for i=1:length(set_3P)
A=[x(set_3P(i,1)) y(set_3P(i,1))];
B=[x(set_3P(i,2)) y(set_3P(i,2))];
C=[x(set_3P(i,3)) y(set_3P(i,3))];
R=minCirclePoints3(A,B,C);
rSet=[rSet;[R,i]];%每行:圆心坐标,半径,第几组(每组包括随机的三个点)
end;
rSet=sortrows(rSet,3);%按照半径排序
% 在四个圆中找一个最小半径圆包含这四个点
for i=1:size(rSet,1)
for j=1:4
if sqrt((rSet(i,1)-(P(j,1) ))^2+ ( rSet(i,2)-(P(j,2)))^2) >rSet(i,3)%这个圆不行
break;
end
end;
if j>4%第i组三个点产生的圆可行--必然可以找到一个
break;
end;
end;
mc=rSet(i,4);
A=[x(set_3P(mc,1)) y(set_3P(mc,1))];
B=[x(set_3P(mc,2)) y(set_3P(mc,2))];
C=[x(set_3P(mc,3)) y(set_3P(mc,3))];
end;