專業課程設計的作業,當初花了差不多三個晚上最后終於實現了Edmonds算法並解決該問題,最后還學會了用Matlab做簡單的交互界面,算是到目前為止本人自我感覺寫得最成功的程序,以防將來再重裝系統導致文件丟失,所以發上來,歡迎大家發郵件交流指正交流.
如果對於二分圖最大匹配算法不熟悉,可以參考前篇博文:http://www.cnblogs.com/visayafan/archive/2012/05/12/2496896.html
一共有RecuCal.m LockMap.m BuildMatrix.m Edmonds.m GUI1.m 這幾個文件,我把它們合到一塊粘上去了,你再把他們分開保存就可以了.
其中前三個文件都是為建立鄰接矩陣服務的,Edmonds.m是匈牙利算法的主文件,GUI1.m只是調用Edmonds.m做個界面而已。
調用關系是GUI1.m調用Edmonds.m; Edmonds.m調用BuildMatrix.m和LockMap.m ;LockMap.m調用RecuCal.m
最后運行GUI1.m就ok了
#LockMap.m function [LMA, LMB] = LockMap(n, m) % LOCKMAP - 求解滿足條件鎖並設置相應的映射 % 輸入參數:n 表槽數,m 表高度數。 % 輸出參數:LMA,LMB 分別為二維矩陣表示自然數到滿足條件鎖之間的映射。 global jiA ouB ary A B mm N N = n; mm = m; jiA=0; ouB=0; A=[]; B=[]; ary = zeros(1, n); RecuCal(n); LMA=A; LMB=B; [lena, n] = size(LMA); [lenb, n] =size(LMB); if lena>lenb temp = LMA; LMA=LMB;LMB=temp; temp = lena;lena=lenb;lenb=temp; end #RecuCal.m function RecuCal(n) % RECUCAL - 遞歸函數 global jiA ouB ary A B mm N if n ==1 for k=1:mm % 調用遞歸函數時要用到的變量所以 % 設為全局 ary(1) = k; Max = max(ary); Min = min(ary); num = 0; neighbor = 0; for i=1:N num = num + (Max-ary(i))*(ary(i)-Min); if (i~=N) neighbor = max(neighbor, abs(ary(i)-ary(i+1))); end end if (neighbor > mm-1.5)&&(num > 0.5) if mod(sum(ary), 2) % 奇數,屬於 A 類 jiA = jiA+1; A(jiA,:) = ary; else % 偶數,屬於 B 類 ouB = ouB+1; B(ouB,:) = ary; end end end else for k=1:mm ary(n) = k; RecuCal(n-1); end end #BuildMatrix.m function AB = BuildMatrix(LMA, LMB) % BUILDMATRIX - 建立鄰接矩陣,若 i 與 j 之間可以互開則 AB(i,j)=1,否則為 0。 AB = []; [lena, n] = size(LMA); [lenb, n] =size(LMB); for i = 1:lena for j=1:lenb tmp = 0; for k=1:n tmp = tmp + abs(LMA(i,k)-LMB(j,k)); end if tmp == 1 AB(i, j)=1; end end end #Edmonds.m function str = Edmonds(n, m) % EDMONDS - Edmonds 算法尋找完美匹配 str = []; [LMA, LMB] = LockMap(n, m); AB = BuildMatrix(LMA, LMB); lena = length(LMA); lenb = length(LMB); if lena==0 disp('其中一個分組為空, 無法匹配'); %當 n=m=3 時只有偶數組無奇數組, 不能完成 匹配 return; end MatA = zeros(1, lena); MatB = zeros(1, lenb); X = MatA; Y=MatB; Z=Y; NumNoMat = 0; % 無法匹配的點的個數 % 最初匹配,只有一個匹配 j = find(AB(1,:), 1); MatA(1)=j; MatB(j)=1; while length(find(MatA==0)) ~= 0 % 存在不匹配的元素 J = find(MatA==0); i = J(1); % 第 i 個元素未被匹配 init = i; X(i)=0; J = find(AB(i,:)); % J 為所有與 i 相鄰結點 Y(J) = i; j=J(1); while ~isempty(find(Y~=Z)) if MatB(j) ~= 0 % j 是匹配點 Z(j) = Y(j); i = MatB(j); X(i)=j; J = find(AB(i,:)); Y(J)=i; J = find(Y); JJ = find(Z); J = setxor(intersect(J, JJ), J); j=J(1); else % j 不是匹配點 i = Y(j); MatA(i) = j; MatB(j) = i; while X(i) j = X(i); i = Z(j); MatA(i) = j; MatB(j) = i; end break; end end % 如果 Y==Z 則表明該點沒有與之相應的匹配,即不存在完美匹配,在 MatA 中標 % 記為-1。 if isempty(find(Y~=Z, 1)) NumNoMat = NumNoMat + 1; MatA(init) = -1; end X(1:lena)=0; Y(1:lenb)=0; Z=Y; end total = 0; for i=1:lena k = MatA(i); if k<=0 continue; end % k<=0 時表明匹配不存在 stra = ''; strb = ''; for j=1:n stra = [stra, num2str(LMA(i, j)), ' ']; strb = [strb, num2str(LMB(k, j)), ' ']; end str = [str, stra, '------ ', strb, 10]; total = total + 1; end str = [str, '匹配個數有:', num2str(total)]; #GUI1.m function varargout = GUI1(varargin) gui_Singleton = 1; gui_State = struct('gui_Name', mfilename, ... 'gui_Singleton', gui_Singleton, ... 'gui_OpeningFcn', @GUI1_OpeningFcn, ... 'gui_OutputFcn', @GUI1_OutputFcn, ... 'gui_LayoutFcn', [] , ... 'gui_Callback', []); if nargin && ischar(varargin{1}) gui_State.gui_Callback = str2func(varargin{1}); end if nargout [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:}); else gui_mainfcn(gui_State, varargin{:}); end % End initialization code - DO NOT EDIT % --- Executes just before GUI1 is made visible. function GUI1_OpeningFcn(hObject, eventdata, handles, varargin) handles.output = hObject; guidata(hObject, handles); function varargout = GUI1_OutputFcn(hObject, eventdata, handles) varargout{1} = handles.output; function pushbutton1_Callback(hObject, eventdata, handles) a = get(handles.edit1, 'String'); b = get(handles.edit2, 'String'); str = Edmonds(str2num(a), str2num(b)); set(handles.edit4, 'String', str); guidata(hObject, handles); function edit1_Callback(hObject, eventdata, handles) input = str2num(get(hObject, 'String')); guidata(hObject, handles); function edit1_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end function edit2_Callback(hObject, eventdata, handles) input = str2num(get(hObject, 'String')); guidata(hObject, handles); function edit2_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end function slider1_Callback(hObject, eventdata, handles) function slider1_CreateFcn(hObject, eventdata, handles) if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor',[.9 .9 .9]); end function text_result_Callback(hObject, eventdata, handles) function text_result_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end function edit4_Callback(hObject, eventdata, handles) function edit4_CreateFcn(hObject, eventdata, handles) if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor')) set(hObject,'BackgroundColor','white'); end function pushbutton2_Callback(hObject, eventdata, handles) set(handles.edit4, 'String', ''); set(handles.edit1, 'String', ''); set(handles.edit2, 'String', '');