add
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MAX_VERTICES 5 // 图的最大顶点数
|
||||
|
||||
// 图的邻接矩阵表示
|
||||
int graph[MAX_VERTICES][MAX_VERTICES] = {
|
||||
{0, 1, 1, 0, 0},
|
||||
{1, 0, 1, 1, 0},
|
||||
{1, 1, 0, 0, 1},
|
||||
{0, 1, 0, 0, 1},
|
||||
{0, 0, 1, 1, 0}
|
||||
};
|
||||
|
||||
bool visited[MAX_VERTICES]; // 访问标记数组,用来记录哪些节点已经被访问过
|
||||
|
||||
// 队列结构
|
||||
typedef struct {
|
||||
int items[MAX_VERTICES]; // 队列的数组表示
|
||||
int front; // 队列的前端
|
||||
int rear; // 队列的尾端
|
||||
} Queue;
|
||||
|
||||
// 队列操作函数
|
||||
|
||||
// 初始化队列
|
||||
void initQueue(Queue *q) {
|
||||
q->front = 0;
|
||||
q->rear = -1; // 队列初始化为空
|
||||
}
|
||||
|
||||
// 检查队列是否为空
|
||||
int isEmpty(Queue *q) {
|
||||
return q->front > q->rear;
|
||||
}
|
||||
|
||||
// 入队操作
|
||||
void enqueue(Queue *q, int value) {
|
||||
if (q->rear < MAX_VERTICES - 1) { // 如果队列未满
|
||||
q->items[++(q->rear)] = value; // 将新元素添加到队列的尾端
|
||||
}
|
||||
}
|
||||
|
||||
// 出队操作
|
||||
int dequeue(Queue *q) {
|
||||
if (!isEmpty(q)) {
|
||||
return q->items[(q->front)++]; // 从队列的前端取出一个元素
|
||||
}
|
||||
return -1; // 队列为空时返回 -1
|
||||
}
|
||||
|
||||
// 广度优先遍历 BFS 函数
|
||||
void bfs(int start, int n) {
|
||||
Queue q;
|
||||
initQueue(&q); // 初始化队列
|
||||
|
||||
enqueue(&q, start); // 将起始节点入队
|
||||
visited[start] = true; // 标记起始节点已访问
|
||||
|
||||
while (!isEmpty(&q)) { // 队列不为空时,继续遍历
|
||||
int current = dequeue(&q); // 从队列中取出一个节点
|
||||
printf("%d ", current); // 输出当前节点
|
||||
|
||||
// 遍历当前节点的所有邻接节点
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (graph[current][i] == 1 && !visited[i]) { // 如果当前节点和 i 节点之间有边且 i 节点未被访问
|
||||
enqueue(&q, i); // 将 i 节点入队
|
||||
visited[i] = true; // 标记 i 节点已访问
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n = MAX_VERTICES; // 图的顶点数
|
||||
for (int i = 0; i < n; i++) {
|
||||
visited[i] = false; // 初始化访问标记数组,将所有节点标记为未访问
|
||||
}
|
||||
|
||||
printf("广度优先遍历(BFS):\n");
|
||||
bfs(0, n); // 从顶点 0 开始进行 BFS 遍历
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,41 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define MAX_VERTICES 5 // 图的最大顶点数
|
||||
|
||||
// 图的邻接矩阵表示
|
||||
int graph[MAX_VERTICES][MAX_VERTICES] = {
|
||||
{0, 1, 1, 0, 0},
|
||||
{1, 0, 1, 1, 0},
|
||||
{1, 1, 0, 0, 1},
|
||||
{0, 1, 0, 0, 1},
|
||||
{0, 0, 1, 1, 0}
|
||||
};
|
||||
|
||||
bool visited[MAX_VERTICES]; // 访问标记数组,用来记录哪些节点已经被访问过
|
||||
|
||||
// 深度优先遍历 DFS 函数
|
||||
void dfs(int v, int n) {
|
||||
printf("%d ", v); // 输出当前节点
|
||||
visited[v] = true; // 标记当前节点已访问
|
||||
|
||||
// 递归访问当前节点的所有未访问的邻接节点
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (graph[v][i] == 1 && !visited[i]) { // 如果存在边且该邻接节点未被访问
|
||||
dfs(i, n); // 递归调用,访问该邻接节点
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
int n = MAX_VERTICES; // 图的顶点数
|
||||
for (int i = 0; i < n; i++) {
|
||||
visited[i] = false; // 初始化访问标记数组,将所有节点标记为未访问
|
||||
}
|
||||
|
||||
printf("深度优先遍历(DFS):\n");
|
||||
dfs(0, n); // 从顶点 0 开始进行 DFS 遍历
|
||||
printf("\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,78 @@
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#define MAX_CITIES 4 // 设定城市数量为4
|
||||
#define INF INT_MAX
|
||||
int n = MAX_CITIES; // 城市数量
|
||||
int dist[MAX_CITIES][MAX_CITIES] = { // 距离矩阵
|
||||
{0, 30, 6, 4}, // 城市 0 到其他城市的距离
|
||||
{30, 0, 5, 10}, // 城市 1 到其他城市的距离
|
||||
{6, 5, 0, 20}, // 城市 2 到其他城市的距离
|
||||
{4, 10, 20, 0} // 城市 3 到其他城市的距离
|
||||
};
|
||||
int bestPath[MAX_CITIES]; // 最优路径
|
||||
int bestCost = INF; // 最优路径的总成本
|
||||
// 计算从节点current到下一个节点的界限
|
||||
int calculateLowerBound(int path[], int current) {
|
||||
int lowerBound = 0;
|
||||
int visited[MAX_CITIES] = {0};
|
||||
// 计算已访问的路径的距离
|
||||
for (int i = 0; i < current; i++) {
|
||||
lowerBound += dist[path[i]][path[i + 1]];
|
||||
visited[path[i]] = 1;
|
||||
}
|
||||
// 计算当前节点到其他未访问节点的最短距离
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (!visited[i]) {
|
||||
int minDist = INF;
|
||||
for (int j = 0; j < n; j++) {
|
||||
if (!visited[j] && dist[i][j] < minDist) {
|
||||
minDist = dist[i][j];
|
||||
}
|
||||
}
|
||||
lowerBound += minDist;
|
||||
}
|
||||
}
|
||||
return lowerBound;
|
||||
}
|
||||
// 分支限界法求解TSP
|
||||
void branchAndBound(int path[], int current, int cost) {
|
||||
if (current == n) {
|
||||
// 所有城市都已访问,检查是否是最优解
|
||||
cost += dist[path[current - 1]][path[0]]; // 加上返回起点的距离
|
||||
if (cost < bestCost) {
|
||||
bestCost = cost;
|
||||
for (int i = 0; i < n; i++) {
|
||||
bestPath[i] = path[i];
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
// 计算当前路径的界限
|
||||
int lowerBound = cost + calculateLowerBound(path, current);
|
||||
// 如果当前解已经不可能优于最优解,剪枝
|
||||
if (lowerBound >= bestCost) return;
|
||||
// 继续扩展路径
|
||||
for (int i = 0; i < n; i++) {
|
||||
int flag = 0;
|
||||
for (int j = 0; j < current; j++) {
|
||||
if (path[j] == i) {
|
||||
flag = 1; // 检查当前城市是否已访问
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (flag == 0) {
|
||||
path[current] = i;
|
||||
branchAndBound(path, current + 1, cost + dist[path[current - 1]][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
int main() {
|
||||
int path[MAX_CITIES];
|
||||
path[0] = 0; // 从第一个城市出发
|
||||
branchAndBound(path, 1, 0);
|
||||
printf("\n最优路径是: ");
|
||||
for (int i = 0; i < n; i++)
|
||||
printf("%d ", bestPath[i]);
|
||||
printf("\n总路程: %d\n", bestCost);
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,43 @@
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#define MAX_CITIES 4 // 城市数量
|
||||
#define INF INT_MAX
|
||||
int n = MAX_CITIES; // 城市数量
|
||||
int dist[MAX_CITIES][MAX_CITIES] = {
|
||||
{0, 30, 6, 4}, {30, 0, 5, 10},
|
||||
{6, 5, 0, 20}, {4, 10, 20, 0}
|
||||
};
|
||||
int visited[MAX_CITIES]; // 标记城市是否访问
|
||||
int bestPath[MAX_CITIES]; // 最优路径
|
||||
int bestCost = INF; // 最优路径的总成本
|
||||
// 回溯法求解TSP
|
||||
void backtrack(int currentCity, int count, int cost, int path[]) {
|
||||
if (count == n) { // 所有城市都已访问,检查是否是最优解
|
||||
cost += dist[currentCity][0]; // 加上返回起点的距离
|
||||
if (cost < bestCost) {
|
||||
bestCost = cost;
|
||||
for (int i = 0; i < n; i++)
|
||||
bestPath[i] = path[i];
|
||||
}
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < n; i++) {// 尝试所有未访问的城市
|
||||
if (!visited[i]) { // 访问城市i
|
||||
visited[i] = 1; path[count] = i;
|
||||
// 递归访问下一个城市
|
||||
backtrack(i, count + 1, cost + dist[currentCity][i], path);
|
||||
visited[i] = 0; // 回溯
|
||||
}
|
||||
}
|
||||
}
|
||||
int main() {
|
||||
int path[MAX_CITIES];
|
||||
visited[0] = 1; // 从第一个城市出发
|
||||
path[0] = 0; // 起点是城市0
|
||||
backtrack(0, 1, 0, path); // 从城市0开始回溯
|
||||
printf("\n最优路径是: ");
|
||||
for (int i = 0; i < n; i++)
|
||||
printf("%d ", bestPath[i]);
|
||||
printf("\n最小路程: %d\n", bestCost);
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,90 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#define CAPACITY 30
|
||||
#define N 3
|
||||
#define QUEUE_SIZE 100 // 定义队列的最大容量(静态分配)
|
||||
typedef struct {// 定义节点结构体
|
||||
int level; // 当前节点所在的层数(即考虑第几个物品)
|
||||
int weight; // 当前已装入物品的总重量
|
||||
int value; // 当前已获得的总价值
|
||||
bool items[N]; // 布尔数组,记录每个物品是否被选择
|
||||
} Node;
|
||||
// 定义队列结构体,使用数组模拟队列
|
||||
typedef struct {
|
||||
Node liveList[QUEUE_SIZE]; // 队列的存储数组
|
||||
int front, rear; // 队列的头部和尾部指针
|
||||
} Queue;
|
||||
// 初始化队列,设置front为0,rear为-1表示空队列
|
||||
void initQueue(Queue* queue) {
|
||||
queue->front = 0; queue->rear = -1;
|
||||
}
|
||||
// 检查队列是否为空,如果front大于rear则为空
|
||||
int isEmpty(Queue* queue) {
|
||||
return queue->front > queue->rear;
|
||||
}
|
||||
// 向队列中添加元素,使用前置自增保证新元素放置在正确位置
|
||||
void insertQueue(Queue* queue, Node item) {
|
||||
queue->liveList[++(queue->rear)] = item;
|
||||
}
|
||||
// 从队列中移除并返回元素,如果队列为空则返回一个空节点
|
||||
Node popQueue(Queue* queue) {
|
||||
if (isEmpty(queue)) {
|
||||
static Node emptyNode = {-1, -1, -1, {false}};
|
||||
return emptyNode;
|
||||
}
|
||||
return queue->liveList[(queue->front)++];
|
||||
}
|
||||
// 使用广度优先搜索(BFS)解决01背包问题
|
||||
void bag01bfs(Queue* queue, int weightArr[], int value[], int n, int maxWeight,
|
||||
int* maxValue, bool bestItems[]) {
|
||||
// 创建初始节点(level=0,weight=0,value=0,items全为false),并将其加入队列
|
||||
Node node = {0, 0, 0, {false}};
|
||||
insertQueue(queue, node);
|
||||
while (!isEmpty(queue)) { // 开始广度优先搜索
|
||||
Node u = popQueue(queue); // 取出队列中的第一个节点
|
||||
// 如果遇到空节点,跳过本次循环
|
||||
if (u.level == -1) continue;
|
||||
if (u.level == n) { // 如果到达最后一层(所有物品都考虑完毕)
|
||||
if (u.value > *maxValue) { // 更新最大价值和最优解
|
||||
*maxValue = u.value;
|
||||
for (int i = 0; i < N; ++i)
|
||||
bestItems[i] = u.items[i];
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// 分支:包含当前物品的情况
|
||||
if (u.weight + weightArr[u.level] <= maxWeight) {
|
||||
// 创建新节点v,代表选择了当前物品的情况
|
||||
Node v = {u.level + 1, u.weight + weightArr[u.level], u.value + value[u.level]};
|
||||
for (int i = 0; i < N; ++i)
|
||||
v.items[i] = u.items[i];
|
||||
v.items[u.level] = true;
|
||||
insertQueue(queue, v);
|
||||
}
|
||||
// 分支:不包含当前物品的情况
|
||||
Node w = {u.level + 1, u.weight, u.value};
|
||||
for (int i = 0; i < N; ++i)
|
||||
w.items[i] = u.items[i];
|
||||
insertQueue(queue, w);
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
// 定义每个物品的重量和价值
|
||||
int weightArr[N] = {16, 15, 15}; // 每个物品的重量
|
||||
int value[N] = {45, 25, 25}; // 每个物品的价值
|
||||
int maxValue = 0; // 最大价值
|
||||
bool bestItems[N] = {false}; // 记录最优解的物品选择情况
|
||||
Queue queue;
|
||||
initQueue(&queue); // 初始化队列
|
||||
// 调用bag01bfs函数解决背包问题
|
||||
bag01bfs(&queue, weightArr, value, N, CAPACITY, &maxValue, bestItems);
|
||||
// 输出结果
|
||||
printf("最大价值是 %d\n", maxValue);
|
||||
printf("选择的物品:");
|
||||
for (int i = 0; i < N; ++i) {
|
||||
if (bestItems[i])
|
||||
printf("%d ", i + 1); // 输出物品编号(从1开始)
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1,176 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define N 3 // 物品数量
|
||||
#define CAPACITY 30 // 背包容量
|
||||
#define MAX_NODES (N * 2) // 估计的最大节点数
|
||||
|
||||
// 物品结构体
|
||||
typedef struct {
|
||||
int weight;
|
||||
int value;
|
||||
} Item;
|
||||
|
||||
// 活结点结构体
|
||||
typedef struct {
|
||||
int level; // 当前节点的层级
|
||||
int profit; // 当前节点的价值
|
||||
int weight; // 当前节点的重量
|
||||
float bound; // 当前节点的上界
|
||||
} Node;
|
||||
|
||||
// 优先队列(最大堆)
|
||||
typedef struct {
|
||||
Node nodes[MAX_NODES];
|
||||
int size;
|
||||
} PriorityQueue;
|
||||
|
||||
// 初始化优先队列
|
||||
void initQueue(PriorityQueue* pq) {
|
||||
pq->size = 0;
|
||||
}
|
||||
|
||||
// 插入节点到优先队列
|
||||
void insert(PriorityQueue* pq, Node node) {
|
||||
if (pq->size == MAX_NODES) {
|
||||
printf("Priority queue is full.\n");
|
||||
return;
|
||||
}
|
||||
int i = pq->size++;
|
||||
while (i > 0 && pq->nodes[(i - 1) / 2].bound < node.bound) {
|
||||
pq->nodes[i] = pq->nodes[(i - 1) / 2];
|
||||
i = (i - 1) / 2;
|
||||
}
|
||||
pq->nodes[i] = node;
|
||||
}
|
||||
|
||||
// 删除并返回优先队列的最大元素
|
||||
Node removeMax(PriorityQueue* pq) {
|
||||
if (pq->size <= 0) {
|
||||
printf("Priority queue is empty.\n");
|
||||
exit(1);
|
||||
}
|
||||
Node max = pq->nodes[0];
|
||||
pq->nodes[0] = pq->nodes[--pq->size];
|
||||
int i = 0;
|
||||
while (2 * i + 1 < pq->size) {
|
||||
int left = 2 * i + 1;
|
||||
int right = 2 * i + 2;
|
||||
int largest = i;
|
||||
if (left < pq->size && pq->nodes[left].bound > pq->nodes[largest].bound)
|
||||
largest = left;
|
||||
if (right < pq->size && pq->nodes[right].bound > pq->nodes[largest].bound)
|
||||
largest = right;
|
||||
if (largest != i) {
|
||||
Node temp = pq->nodes[i];
|
||||
pq->nodes[i] = pq->nodes[largest];
|
||||
pq->nodes[largest] = temp;
|
||||
i = largest;
|
||||
} else break;
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
// 计算节点的上界(bound),这是通过贪心策略估计的最大可能价值
|
||||
float calculateBound(Node u, int n, int W, Item items[]) {
|
||||
if (u.weight >= W) return 0;
|
||||
|
||||
int j = u.level + 1;
|
||||
float bound = u.profit;
|
||||
int totalWeight = u.weight;
|
||||
|
||||
// 从当前节点继续往下选择物品的贪心解(按单位价值排序)
|
||||
while (j < n && totalWeight + items[j].weight <= W) {
|
||||
totalWeight += items[j].weight;
|
||||
bound += items[j].value;
|
||||
j++;
|
||||
}
|
||||
|
||||
if (j < n) {
|
||||
bound += (W - totalWeight) * ((float)items[j].value / items[j].weight);
|
||||
}
|
||||
|
||||
return bound;
|
||||
}
|
||||
|
||||
// 比较函数,用于qsort排序
|
||||
int compareItems(const void* a, const void* b) {
|
||||
Item* itemA = (Item*)a;
|
||||
Item* itemB = (Item*)b;
|
||||
float unitValueA = (float)itemA->value / itemA->weight;
|
||||
float unitValueB = (float)itemB->value / itemB->weight;
|
||||
return (unitValueB - unitValueA) > 0 ? 1 : -1;
|
||||
}
|
||||
|
||||
// 0-1 背包问题的分支限界法
|
||||
int knapsackBranchAndBound(Item items[], int n, int W) {
|
||||
// 按照单位价值对物品进行排序
|
||||
qsort(items, n, sizeof(Item), compareItems);
|
||||
|
||||
PriorityQueue pq;
|
||||
initQueue(&pq);
|
||||
|
||||
// 初始化第一个节点
|
||||
Node u = { -1, 0, 0, 0.0 };
|
||||
insert(&pq, u);
|
||||
|
||||
int maxProfit = 0;
|
||||
|
||||
while (pq.size > 0) {
|
||||
// 取出优先队列中的最大元素
|
||||
u = removeMax(&pq);
|
||||
|
||||
// 如果当前节点的 bound 值不大于最大收益,则剪枝
|
||||
if (u.bound <= maxProfit) continue;
|
||||
|
||||
// 尝试将下一个物品放入背包
|
||||
Node v = u;
|
||||
v.level++;
|
||||
|
||||
if (v.level < n) {
|
||||
// 选择第 v.level 个物品
|
||||
if (v.weight + items[v.level].weight <= W) {
|
||||
v.weight += items[v.level].weight;
|
||||
v.profit += items[v.level].value;
|
||||
if (v.profit > maxProfit) {
|
||||
maxProfit = v.profit;
|
||||
}
|
||||
v.bound = calculateBound(v, n, W, items);
|
||||
if (v.bound > maxProfit) {
|
||||
insert(&pq, v);
|
||||
}
|
||||
}
|
||||
|
||||
// 不选择第 v.level 个物品
|
||||
v = u;
|
||||
v.level++;
|
||||
v.bound = calculateBound(v, n, W, items);
|
||||
if (v.bound > maxProfit) {
|
||||
insert(&pq, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maxProfit;
|
||||
}
|
||||
|
||||
int main() {
|
||||
// 已经填写的数据
|
||||
int weightArr[N] = {16, 15, 15}; // 每个物品的重量
|
||||
int valueArr[N] = {45, 25, 25}; // 每个物品的价值
|
||||
|
||||
// 初始化物品数组
|
||||
Item items[N];
|
||||
for (int i = 0; i < N; i++) {
|
||||
items[i].weight = weightArr[i];
|
||||
items[i].value = valueArr[i];
|
||||
}
|
||||
|
||||
// 调用分支限界法求解0-1背包问题
|
||||
int maxProfit = knapsackBranchAndBound(items, N, CAPACITY);
|
||||
|
||||
// 输出最大收益
|
||||
printf("Maximum profit: %d\n", maxProfit);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user