?? 最佳匹配·可視化.cpp
字號:
#include <windows.h>
#include <stdio.h>
HWND hwnd;
char str[255];
const int SCREEN_WIDTH = 640, SCREEN_HEIGHT = 480;
const int UP_MARGIN = SCREEN_HEIGHT / 4, DOWN_MARGIN = SCREEN_HEIGHT / 3;
int maxX, maxY; /* screen dimensions */
HDC hdc, memdc; /* store the virtual device handle */
HBITMAP hbit; /* store the virtual bitmap */
HBRUSH hbrush; /* store the brush handle */
HGDIOBJ hOldbit,hOldbrush;
HPEN hOldpen; /* handle of old pen */
HPEN hRedpen, hGreenpen, hBluepen, hYellowpen; /* create pens */
PAINTSTRUCT paintstruct;
char szWinName[] = "MyWin"; /* name of window class */
LRESULT CALLBACK WindowFunc(HWND, UINT, WPARAM, LPARAM);
#include <iostream.h> // 為了調用 cout 函數
#include <stdlib.h> // 為了調用 srand 和 rand 函數
#include <time.h> // 為了調用 time 函數
const int VERTEX_OF_X = 5; // 設置二分圖 G 中 X 點集的大小為 VERTEX_OF_X
const int VERTEX_OF_Y = 5; // 設置二分圖 G 中 Y 點集的大小為 VERTEX_OF_Y
const int MIN_WEIGHT = 0; // 設置二分圖 G 中邊權最小值
const int MAX_WEIGHT = 9; // 設置二分圖 G 中邊權最大值
int xPosX[VERTEX_OF_X];
int xPosY[VERTEX_OF_X];
int yPosX[VERTEX_OF_Y];
int yPosY[VERTEX_OF_Y];
signed int Weight[VERTEX_OF_X][VERTEX_OF_Y];// 用于標記二分圖 G = (X, E, Y) 中的已知邊集 E
// 說明:Weight 的值表示邊權(可正可負)。
signed int LabelX[VERTEX_OF_X]; // 用于在尋找最佳匹配過程中對 X 的點作標記
// 說明:LabelX 的值應當滿足 LabelX + LabelY >= Weight[X][Y]。
signed int LabelY[VERTEX_OF_Y]; // 用于在尋找最佳匹配過程中對 Y 的點作標記
// 說明:LabelY 的值應當滿足 LabelX + LabelY >= Weight[X][Y]。
int Edge[VERTEX_OF_X][VERTEX_OF_Y]; // 用于標記二分圖 G = (X, E, Y) 中的已知邊集 E
// 說明:Edge 的值為 0 表示無,為 1 表示有。
int Match[VERTEX_OF_X][VERTEX_OF_Y]; // 用于標記二分圖 G = (X, E, Y) 中的最佳匹配 M
// 說明:Match 的值為 0 表示無,1 表示有。
void InitWeight(); // 用于初始化 Weight
void InitLabelX(); // 用于初始化 LabelX
void InitLabelY(); // 用于初始化 LabelY
void InitEdge(); // 用于初始化 Edge
void InitMatch(); // 用于初始化 Match
void DisplayWeight(); // 用于顯示 Weight
void DisplayLabelX(); // 用于顯示 LabelX
void DisplayLabelY(); // 用于顯示 LabelY
void DisplayEdge(); // 用于顯示 Edge
void DisplayMatch(); // 用于顯示 Match
void GenerateWeight(); // 用于隨機產生 Weight
void GenerateInitialMatch(); // 用于產生初始化匹配 Match
void GetFeasibleVertexLabeling(); // 對二分圖 G 進行任意可行頂點標號 L
void DetermineEqualitySubgraph(); // 確定相對應于 L 的等同子圖 GL
void GenerateOptimalAssignment(); // 用于產生最佳匹配
int GetNumberOfWeight(); // 用于獲取邊集 Weight 的大小
int GetNumberOfEdge(); // 用于獲取等同子圖 GL 的邊集 Edge 的大小
int GetSizeOfMatch(); // 用于獲取匹配 M 的大小
int IsMCompleteForG(); // 確定 Match 是否為 Weight 的完美匹配
int S[VERTEX_OF_X]; // 用于產生最佳匹配,存放 X 的頂點
int T[VERTEX_OF_Y]; // 用于產生最佳匹配,存放 Y 的頂點
int JS[VERTEX_OF_Y]; // 用于產生最佳匹配,存放 X 的鄰接頂點
int TC[VERTEX_OF_Y]; // 用于產生最佳匹配,存放 Y 的頂點,是 T 關于 Y 的補集
int SizeOfS; // 用于記錄集合 S 的當前大小
int SizeOfT; // 用于記錄集合 T 的當前大小
int SizeOfJS; // 用于記錄集合 JS 的當前大小
int SizeOfTC; // 用于記錄集合 TC 的當前大小
void InitS(); // 用于初始化 S
void InitT(); // 用于初始化 T
void InitJS(); // 用于初始化 JS
void InitTC(); // 用于初始化 TC
void DisplayS(); // 用于顯示 S
void DisplayT(); // 用于顯示 T
void DisplayJS(); // 用于顯示 JS
void DisplayTC(); // 用于顯示 TC
int GenerateS(); // 產生 S 并對其進行整理(包含排序和去重)
void DefragT(); // 對 T 進行整理(包含排序和去重)
void GenerateJS(); // 產生 JS 并對其進行整理(包含排序和去重)
void GenerateTC(); // 產生 TC 并對其進行整理(包含排序和去重)
int IsJSEqualT(); // 判斷 JS 和 T 是否相等
int Al; // 用于存放 Al 的值
int FindAl(); // 計算 Al 的值并返回
void ConstructANewLabeling(); // 構建一個新的標號 L'
void FindMAlternatingPath(int x); // 發現一個從 X 到 Y 的 M - 交錯路徑
void GenerateLargerMatching(int y); // 根據 M - 交錯路徑 產生 Gl 中的一個更大的匹配 M'
int GetSumOfWeight(); // 計算最佳匹配中的邊權之和
signed int MarkX[VERTEX_OF_X]; // 用于在尋找 M - 交錯路徑 過程中對 X 的點作標記
// 說明:MarkX 的值為 -2(初始無標記),-1(標記為 * ),j(標記為 Yj)。
signed int MarkY[VERTEX_OF_Y]; // 用于在尋找 M - 交錯路徑 過程中對 Y 的點作標記
// 說明:MarkY 的值為 -2(初始無標記),-1(標記為 * ),i(標記為 Xi)。
signed int ScanX[VERTEX_OF_X]; // 用于在尋找 M - 交錯路徑 過程中對 X 的點作掃描
// 說明:ScanX 的值為 0(初始未掃描),1(已掃描)。
signed int ScanY[VERTEX_OF_Y]; // 用于在尋找 M - 交錯路徑 過程中對 Y 的點作掃描
// 說明:ScanX 的值為 0(初始未掃描),1(已掃描)。
void InitMarkX(); // 用于初始化 MarkX
void InitMarkY(); // 用于初始化 MarkY
void InitScanX(); // 用于初始化 ScanX
void InitScanY(); // 用于初始化 ScanY
void DisplayMarkX(); // 用于顯示 MarkX
void DisplayMarkY(); // 用于顯示 MarkY
void DisplayScanX(); // 用于顯示 ScanX
void DisplayScanY(); // 用于顯示 ScanY
int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs,int nWinMode)
{
MSG msg;
WNDCLASSEX wcl;
/* Define a window class. */
wcl.cbSize = sizeof(WNDCLASSEX);
wcl.hInstance = hThisInst; /* handle to this instance */
wcl.lpszClassName = szWinName; /* window class name */
wcl.lpfnWndProc = WindowFunc; /* window function */
wcl.style = 0; /* default style */
wcl.hIcon = LoadIcon(NULL,IDI_APPLICATION); /* standard icon */
wcl.hIconSm = LoadIcon(NULL,IDI_WINLOGO); /* SMALL ICON */
wcl.hCursor = LoadCursor(NULL,IDC_ARROW); /* cursor style */
/* Specify name of menu resource. This will be overridden. */
wcl.lpszMenuName = NULL; /* main menu */
wcl.cbClsExtra = 0; /* no extra information needed */
wcl.cbWndExtra = 0; /* no extra information needed */
/* Make the windows backgraoud white */
wcl.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
/* Register the window class. */
if(!RegisterClassEx(&wcl))
return 0;
/* Now that a window class has been registered, a window can be created. */
hwnd = CreateWindow(
szWinName, /* name of window class */
"最佳匹配·可視化", /* title */
WS_OVERLAPPEDWINDOW, /* window style - normal */
CW_USEDEFAULT, /* X coordinate - let Winodws decide */
CW_USEDEFAULT, /* Y coordinate - let Windows decide */
SCREEN_WIDTH, /* width - let Windows decide */
SCREEN_HEIGHT, /* height - let Windows decide */
HWND_DESKTOP, /* no parent window */
NULL, /* no menu */
hThisInst, /* handle of this instance of the program */
NULL /* no additional arguments */
);
/* Display the windows. */
ShowWindow(hwnd, nWinMode);
UpdateWindow(hwnd);
// 初始化隨機數發生器
srand((unsigned)time(NULL));
// 初始化 Weight, LabelX, LabelY, Edge, Match
InitWeight();
InitLabelX();
InitLabelY();
InitEdge();
InitMatch();
// 隨機產生二分圖 G 中的有權邊集 Weight
GenerateWeight();
DisplayWeight();
// Start with an arbitrary feasible vertex labeling l, determine Gl, and choose
// an arbitrary matching M in Gl.
// 對二分圖 G 進行任意可行頂點標號 L(Feasible Vertex Labeling),
GetFeasibleVertexLabeling();
//DisplayLabelX();
//DisplayLabelY();
// 并由此確定相對應于 L 的等同子圖 GL 的無權邊集(Equality Subgraph for L)。
DetermineEqualitySubgraph();
//DisplayEdge();
// 尋找等同子圖 GL 中的一個任意的初始化匹配 M
GenerateInitialMatch();
//cout << "初始化匹配為" << endl;
//DisplayMatch();
// 使用 The Kuhn-Munkres Algorithm 算法(亦稱為 the Hungarian method 方法)產生最佳匹配
GenerateOptimalAssignment();
/* Create the message loop. */
while (GetMessage(&msg, NULL, 0, 0)){
TranslateMessage(&msg); /* translate keyboard messages */
DispatchMessage(&msg); /* return control to Windows 98 */
}
return msg.wParam;
}
/* This function is called by Windows 98 and is passed
messages from the message gueue.
*/
LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam)
{
switch(message) {
case WM_CREATE:
/* get screen coordinates */
maxX = GetSystemMetrics(SM_CXSCREEN);
maxY = GetSystemMetrics(SM_CYSCREEN);
/* make a compatible memory image */
hdc = GetDC(hwnd);
memdc = CreateCompatibleDC(hdc);
hbit = CreateCompatibleBitmap(hdc,maxX,maxY);
hOldbit = SelectObject(memdc,hbit);
hbrush = (HBRUSH)GetStockObject(WHITE_BRUSH);
hOldbrush = SelectObject(memdc,hbrush);
PatBlt(memdc,0,0,maxX,maxY,PATCOPY);
hRedpen = CreatePen(PS_SOLID, 2, RGB(255,0,0));
hGreenpen = CreatePen(PS_SOLID, 2, RGB(0,255,0));
hBluepen = CreatePen(PS_SOLID, 2, RGB(0,0,255));
hYellowpen = CreatePen(PS_SOLID, 4, RGB(255,255,0));
hOldpen = (HPEN)SelectObject(memdc,hRedpen);
SelectObject(memdc,hOldpen);
ReleaseDC(hwnd,hdc);
break;
case WM_PAINT:
hdc = BeginPaint(hwnd,&paintstruct); /* get DC */
/* now,copy memory image onto screen */
BitBlt(hdc,0,0,maxX,maxY,memdc,0,0,SRCCOPY);
EndPaint(hwnd,&paintstruct); /* release DC */
break;
case WM_DESTROY: /* terminate the program */
/* delete pens */
DeleteObject(hRedpen);
DeleteObject(hGreenpen);
DeleteObject(hBluepen);
DeleteObject(hYellowpen);
SelectObject(memdc,hOldbrush);
DeleteObject(hbrush);
SelectObject(memdc,hOldbit);
DeleteObject(hbit);
DeleteDC(memdc);
PostQuitMessage(0);
break;
default:
/* Let Windows 98 process any messages not specified in the preceding switch statement. */
return DefWindowProc(hwnd,message,wParam,lParam);
}
return 0;
}
void GenerateOptimalAssignment(){
int i, j, k, x, y, z;
// 1. If M is complete for G, then M is optimal. Stop. Otherwise, there is some unmatched
// x (- X. Set S = {x} and T = NULL.
Step1:
if (IsMCompleteForG() == 1){
//cout << "M is optimal. Stop." << endl;
cout << "最佳匹配(其權和為 " << GetSumOfWeight() << " )為" << endl;
DisplayMatch();
return;
}
else{
//cout << "There is some unmatched x (- X." << endl;
InitS();
x = GenerateS();
//DisplayS();
InitT();
}
// 2. If Jgl(S) != T, go to step 3. Otherwise, Jgl(S) = T. Find
// Al = min { l(x) + l(y) - w(xy) }
// x(-S, y(-Tc
// where Tc denotes the complement of T in Y, and construct a new labeling l' by
// l(v) - Al for v (- S
// l'(v) = l(v) + Al for v (- T
// l(v) otherwise
// Note that Al > 0 and Jgl'(S) != T. Replace l by l' and gl by gl'.
Step2:
InitJS();
GenerateJS();
//DisplayJS();
DefragT();
//DisplayT();
if (IsJSEqualT() == 0){
goto Step3;
}
else{
InitTC();
GenerateTC();
//DisplayTC();
Al = FindAl();
//cout << "Al = " << Al << endl; // Note that Al > 0.
ConstructANewLabeling();
//DisplayLabelX();
//DisplayLabelY();
DetermineEqualitySubgraph();
//DisplayEdge();
InitJS();
GenerateJS();
//DisplayJS();
//cout << "IsJSEqualT() = " << IsJSEqualT() << endl; // Note that JS != T.
}
// 3. Choose a vertex y in Jgl(S), not in T. If y is matched in M, say with z (- X,
// replace S by S + {z} and T by T + {y}, and go to step 2. Otherwise, there will
// be an M-alternating path from x to y, and we may use this path to find a larger
// matching M' in Gl. Replace M by M' and go to step 1.
Step3:
for (j = 0; j < SizeOfJS; j++){
for (k = 0; k < SizeOfT; k++){
if (T[k] == JS[j]){
break;
}
}
if (k == SizeOfT){
y = JS[j];
break;
}
}
for (i = 0; i < VERTEX_OF_X; i++){
if (Match[i][y] == 1){
z = i;
break;
}
}
if (i != VERTEX_OF_X){
S[SizeOfS++] = z;
T[SizeOfT++] = y;
goto Step2;
}
else{
InitMarkX(); InitMarkY(); InitScanX(); InitScanY();
//DisplayMarkX(); DisplayMarkY(); DisplayScanX(); DisplayScanY();
FindMAlternatingPath(x);
GenerateLargerMatching(y);
goto Step1;
}
}
int GetSumOfWeight(){
int SumOfWeight = 0;
for (int i = 0; i < VERTEX_OF_X; i++){
for (int j = 0; j < VERTEX_OF_Y; j++){
if (Match[i][j] == 1){
SumOfWeight = SumOfWeight + Weight[i][j];
}
}
}
return SumOfWeight;
}
void FindMAlternatingPath(int x){
int i, j, NewMarkAddToX, NewMarkAddToY;
NewMarkAddToX = 0;
MarkX[x] = -1;
NewMarkAddToX++;
while (NewMarkAddToX != 0){
NewMarkAddToY = 0;
for (i = 0; i < VERTEX_OF_X; i++){
if ((MarkX[i] != -2) && (ScanX[i] == 0)){
for (j = 0; j < VERTEX_OF_Y; j++){
if ((MarkY[j] == -2) && (Edge[i][j] == 1) && (Match[i][j] == 0)){
MarkY[j] = i;
NewMarkAddToY++;
}
}
ScanX[i] = 1;
}
}
if (NewMarkAddToY == 0)
return;
NewMarkAddToX = 0;
for (j = 0; j < VERTEX_OF_Y; j++){
if ((MarkY[j] != -2) && (ScanY[j] == 0)){
for (i = 0; i < VERTEX_OF_X; i++){
if ((MarkX[i] == -2) && (Edge[i][j] == 1) && (Match[i][j] == 1)){
MarkX[i] = j;
NewMarkAddToX++;
}
}
ScanY[j] = 1;
}
}
}
}
void GenerateLargerMatching(int y){
int i, j, flag;
flag = 1;
i = MarkY[y];
Match[i][y] = 1;
while (MarkX[i] != -1){
if (flag == 1){
flag = 0;
j = MarkX[i];
Match[i][j] = 0;
}
else{
flag = 1;
i = MarkY[j];
Match[i][j] = 1;
}
}
}
void ConstructANewLabeling(){
for (int i = 0; i < SizeOfS; i++){
LabelX[S[i]] = LabelX[S[i]] - Al;
}
for (int j = 0; j < SizeOfT; j++){
LabelY[T[j]] = LabelY[T[j]] + Al;
}
}
int FindAl(){
int min = LabelX[S[0]] + LabelY[TC[0]] - Weight[S[0]][TC[0]];
for (int i = 0; i < SizeOfS; i++){
for (int j = 0; j < SizeOfTC; j++){
if (LabelX[S[i]] + LabelY[TC[j]] - Weight[S[i]][TC[j]] < min){
min = LabelX[S[i]] + LabelY[TC[j]] - Weight[S[i]][TC[j]];
}
}
}
return min;
}
void GenerateTC(){
int j, k, l, temp;
// Step 1: 產生
for (j = 0; j < VERTEX_OF_Y; j++){
for (k = 0; k < SizeOfT; k++){
if (T[k] == j){
break;
}
}
if (k == SizeOfT)
TC[SizeOfTC++] = j;
}
// Step 2: 排序
for (j = 0; j < SizeOfTC; j++){
for (k = j + 1; k < SizeOfTC; k++){
if (TC[j] > TC[k]){
temp = TC[j];
TC[j] = TC[k];
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -