Datenstrukturen: Probleme bei der Farbgebung von Karten – Anwendungen von Graphen – Backtracking

Inhaltsverzeichnis

Vorwort

Das Problem, das dieses Mal gelöst werden muss: Simulieren Sie einen Teil der Karte mit einem Diagramm, färben Sie die Provinzen ein, verlangen Sie, dass benachbarte Provinzen unterschiedliche Farben verwenden, und stellen Sie sicher, dass die Gesamtzahl der verwendeten Farben möglichst gering ist.

Kommen Sie zunächst zu einem Rendering


1. Ideen zur Problemlösung

Nachdem die Adjazenzmatrix erstellt wurde, verwenden Sie die Backtracking-Funktion, um im Lösungsraumbaum nach allen möglichen Lösungen zu suchen. Wenn ein Farbkonflikt vorliegt, kehren Sie zum vorherigen Knoten zurück. Sobald der Blattknoten erreicht ist, also die Lösung endet, wird dieses Farbschema ausgegeben.

2. Design der Speicherstruktur

a

Abstrakter Datentyp:

        ADT- Diagramm {

        Datenobjekt V : Eine nicht leere Sammlung, alle Elemente in der Sammlung haben die gleichen Eigenschaften.

        Datenrelation R : R={VR} , VR={<x,y> | P(x,y) (x,y ∈ V )}

Grundbetrieb:

        Karte erstellen(&G)

        Betriebsprämisse: Der bekannte Graph G existiert nicht.

        Ergebnis der Operation: Graph G wird erstellt .

        }ADT-Diagramm;

(b) Speicherstruktur: Sequenztabellen-Speicherstruktur

        typedef struct{

           char vertax[MAX][MAX];//Die Provinz, zu der der Scheitelpunkt gehört

           int map[MAX][MAX]; //Adjazenzmatrix

           int n; //Anzahl der Eckpunkte

           int m;//Anzahl der Seiten

        }Graph;

3. Code

1. Erstellen Sie eine Diagrammfunktion

Hier gibt es nicht viel zu sagen, es sind alle Eingaben, die zum Erstellen des Diagramms erforderlich sind. Die Anzahl der Scheitelpunkte, die durch den Scheitelpunkt dargestellte Provinz ist der Name des Scheitelpunkts, die Anzahl der Kanten und die beiden durch Kanten verbundenen Scheitelpunkte.

void Createmap(Graph &G) //创建邻接矩阵
{
	printf("请输入顶点(省份)个数:");
    int f=scanf("%d", &G.n);
    while(f!=1)
	{
		printf("输入值非法!\n");
		printf("请重新输入顶点(省份)个数:");
		fflush(stdin);
		f=scanf("%d", &G.n);
	}
    for(int i=1;i<=G.n;i++)
    {
    	printf("请输入第%d个顶点所代表的省份:",i);
    	cin>>G.vertax[i];
	}
    int u; //顶点1
    int v; //顶点2
    cout << "\n请输入边的个数:";
    cin >> G.m;
    cout << "请输入有边相连的两个顶点u和v:"<< endl;
    for (int i=1;i<=G.m;i++)//为邻接矩阵赋值 
    {
        cin>>u>>v;
        G.map[u][v]=1;
        G.map[v][u]=1;
    }
    cout<<endl;
}

2. Funktion zur Feststellung, ob die Farbnummer gleich ist

Beurteilen Sie zunächst, ob sie verbunden sind. Wenn sie verbunden sind, beurteilen Sie, ob die Farben der beiden Scheitelpunkte gleich sind. Gibt „true“ zurück, wenn die Scheitelpunktfarben nicht in Konflikt stehen, andernfalls wird „false“ zurückgegeben.

bool Find(Graph G,int t) //判断色号是否相同的函数
{
    for(int j=1;j<t;j++) //判断现在扩展点t和前面t-1个顶点有没有相连的
    {
        if(G.map[t][j]) //如果相连
        {
            if(color[j]==color[t]) //且颜色一样
            {
                return false; //返回false,表示需要换个色号尝试
            }
        }
    }
    return true;
}

3. Backtracking-Funktion

Beurteilen Sie, ob der Blattknoten erreicht wurde. Wenn nicht, beginnen Sie mit dem Testen, ob die Farbe dieses Scheitelpunkts in Ordnung ist, führen Sie dann eine Rekursion nach unten durch, geben Sie den nächsten Knoten ein und starten Sie den Farbtest. Wenn nicht, ändern Sie eine andere Farbe und fahren Sie mit dem Testen fort, bis alle Farben vorhanden sind werden getestet.

void Backtrack(Graph G,int t) //回溯函数
{
    if(t>G.n) //到达叶子节点,打印一种填色方案 
    {
    	answer=0;//找到最少的颜色个数 
        sum++; //方案个数+1
        cout << "第"<< sum << "种方案:";
        for (int i=1;i<=G.n;i++)
        {
            cout << color[i] << " ";
        }
        cout << endl;
    }
    else
    {
        for (int i=1;i<=color_nums;i++) //尝试别的色号
        {
            color[t]=i;  //试探色号i 
            if(Find(G,t)) //如果色号没有撞
            {
                Backtrack(G,t+1); //向下递归 
            }
        }
    }
}

4. Gesamtcode

#include <iostream>
using namespace std;
 
const int MAX=111;//最大存储个数 
typedef struct{
	char vertax[MAX][MAX];//顶点所属的省份 
	int map[MAX][MAX]; //邻接矩阵
	int n; //顶点个数
	int m;//边的个数
}Graph; 

int color[MAX]; //解空间,表示第i个省所填的颜色 
int sum=0; //记录有多少种方案

int color_nums=0; //颜色数量
int answer=1;

void Createmap(Graph &G) //创建邻接矩阵
{
	printf("请输入顶点(省份)个数:");
    int f=scanf("%d", &G.n);
    while(f!=1)
	{
		printf("输入值非法!\n");
		printf("请重新输入顶点(省份)个数:");
		fflush(stdin);
		f=scanf("%d", &G.n);
	}
    for(int i=1;i<=G.n;i++)
    {
    	printf("请输入第%d个顶点所代表的省份:",i);
    	cin>>G.vertax[i];
	}
    int u; //顶点1
    int v; //顶点2
    cout << "\n请输入边的个数:";
    cin >> G.m;
    cout << "请输入有边相连的两个顶点u和v:"<< endl;
    for (int i=1;i<=G.m;i++)//为邻接矩阵赋值 
    {
        cin>>u>>v;
        G.map[u][v]=1;
        G.map[v][u]=1;
    }
    cout<<endl;
}
 
bool Find(Graph G,int t) //判断色号是否相同的函数
{
    for(int j=1;j<t;j++) //判断现在扩展点t和前面t-1个顶点有没有相连的
    {
        if(G.map[t][j]) //如果相连
        {
            if(color[j]==color[t]) //且颜色一样
            {
                return false; //返回false,表示需要换个色号尝试
            }
        }
    }
    return true;
}
 
void Backtrack(Graph G,int t) //回溯函数
{
    if(t>G.n) //到达叶子节点,打印一种填色方案 
    {
    	answer=0;//找到最少的颜色个数 
        sum++; //方案个数+1
        cout << "第"<< sum << "种方案:";
        for (int i=1;i<=G.n;i++)
        {
            cout << color[i] << " ";
        }
        cout << endl;
    }
    else
    {
        for (int i=1;i<=color_nums;i++) //尝试别的色号
        {
            color[t]=i;  //试探色号i 
            if(Find(G,t)) //如果色号没有撞
            {
                Backtrack(G,t+1); //向下递归 
            }
        }
    }
}
 
void Print() 
{
	printf("\n最少需要%d种颜色",color_nums);
}

int main()
{
	cout << "用图模拟部分地图,对各省进行着色,要求相邻省所使用的颜色不同,并保证使用的颜色总数最少\n"<< endl;
	Graph G;

    Createmap(G);
    while(answer)
    {
    	color_nums++;//颜色总数+1 
    	Backtrack(G,1);	
	}
	 
    Print();
    return 0;
}

Zusammenfassen

Der Backtracking-Algorithmus übernimmt die Idee, zum nächsten Pfad zurückzukehren, wenn dieser Pfad fehlschlägt. Ich denke, es handelt sich um einen Optimierungsalgorithmus der Brute-Force-Methode, der die erschöpfende Suche der Brute-Force-Methode vermeidet. Dies ist eine Tiefenstrategie. Das heißt, wenn ein bestimmter Knoten die Einschränkungen erfüllt, wird der nächste Knoten weiter getestet, bis eine Lösung gefunden wird. Obwohl die Backtracking-Methode begrenzt ist und die Bereinigungsfunktion den Suchbereich verringert, ähnelt sie dem erschöpfenden Denken, sodass die zeitliche Komplexität immer noch hoch ist, aber auch ein breites Spektrum an Problemlösungen bietet.

Guess you like

Origin blog.csdn.net/Night_Journey/article/details/128566954