目录
HDU1044——Collect More Jewels
题目描述
运行代码
#include <iostream>
#include <string>
#include <cstring>
#include <algorithm>
#include <stack>
#include <queue>
#include <cmath>
#include <vector>
#define ll long long
#define inf 0x3f3f3f3f
#define Max 55
using namespace std;
string mapp[Max];
int w, h, l, m;
//l是时间限制 m是珠宝的数量
int val[Max];//宝石的价值 1-M
int used[Max][Max];//bfs时访问标记
int vis[Max];//dfs时访问
int step[Max][Max];
int ans;//结果
int sum;//所有宝石的价值总和
int dir[4][2] = { {-1,0},{1,0},{0,1},{0,-1} };
int dis[Max][Max];//记录初始位置,各宝石和出口两两间的距离
//从(x1,y1) 点到其他点的距离 s(0-m+1)是改点的标号,0表示初始位置
//m+1表示出口,1-m表示第i个宝物队
queue<int >q;
void bfs(int x1, int y1, int s) { //处理最短距离
while (!q.empty()) q.pop();//必须要
memset(used, 0, sizeof(used));
memset(step, 0, sizeof(step));
int u = x1 * w + y1;//二维转一维
q.push(u);
used[x1][y1] = 1;
step[x1][y1] = 0;
while (!q.empty()) {
u = q.front();
q.pop();
int x = u / w;
int y = u % w;
for (int i = 0; i < 4; i++) {
int xx = x + dir[i][0];
int yy = y + dir[i][1];
if (xx < 0 || xx >= h || yy < 0 || yy >= w)continue;
if (used[xx][yy] || mapp[xx][yy] == '*') continue;
used[xx][yy] = 1;
step[xx][yy] = step[x][y] + 1;
if (mapp[xx][yy] == '@') dis[s][0] = step[xx][yy];
else if (mapp[xx][yy] == '<') dis[s][m + 1] = step[xx][yy];
else if (mapp[xx][yy] >= 'A' && mapp[xx][yy] <= 'J')
dis[s][mapp[xx][yy] - 'A' + 1] = step[xx][yy];
q.push(xx * w + yy);
}
}
}
//dfs ,s表示当前点,value表示获得的价值,time表示花费的时间
void dfs(int s, int value, int time) {
if (time > l) return;//剪枝
if (ans == sum) return;
if (s == m + 1) {//m+1代表出口
if (value > ans) ans = value;
return;
}
for (int i = 0; i <= m + 1; i++) {
if (dis[s][i] == 0 || vis[i]) continue;
vis[i] = 1;
dfs(i, value + val[i], time + dis[s][i]);
vis[i] = 0;
}
}
int main() {
int t;
cin >> t;
for (int Case = 1; Case <= t; Case++) {
memset(dis, 0, sizeof(dis));
cin >> w >> h >> l >> m;
sum = 0;
ans = -1;
for (int i = 1; i <= m; i++) {
cin >> val[i];
sum += val[i];
}
val[0] = val[m + 1] = 0;
for (int i = 0; i < h; i++)
cin >> mapp[i];
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
if (mapp[i][j] == '@') bfs(i, j, 0);//起点到其他……的距离(时间)
else if (mapp[i][j] == '<') bfs(i, j, m + 1);//终点到其他……的距离(时间)
else if (mapp[i][j] >= 'A' && mapp[i][j] <= 'J')
bfs(i, j, mapp[i][j] - 'A' + 1);//宝藏到其他……的距离(时间)
}
}
memset(vis, 0, sizeof(vis));
vis[0] = 1;
dfs(0, 0, 0);//0点是起点
cout << "Case " << Case << ":" << endl;
if (ans >= 0) cout << "The best score is " << ans << "." << endl;
else cout << "Impossible" << endl;
if (Case != t) cout << endl;
}
return 0;
}
代码思路
-
全局变量声明:
mapp[Max]
:存储地图。w
,h
,l
,m
:地图的宽度、高度、时间限制以及宝石的数量。val[Max]
:存储每个宝石的价值。used[Max][Max]
,step[Max][Max]
:在BFS中用于标记已访问的单元格并计算距离。vis[Max]
:在DFS中用于跟踪已访问的宝石。ans
:存储可达到的最大值。sum
:所有宝石价值的总和。dir[4][2]
:移动的方向(上、下、右、左)。dis[Max][Max]
:存储地图上各点之间的最短距离。
-
BFS 函数 (
bfs
):- 此函数使用广度优先搜索(Breadth-First Search)来计算从给定点到地图上所有其他点的最短路径。
- 它使用队列
q
来执行BFS。 - 它更新
dis
矩阵以包含最短距离。
-
DFS 函数 (
dfs
):- 此函数执行深度优先搜索(Depth-First Search),从当前点探索所有可能的路径。
- 它检查当前路径是否能导致比当前最佳值(
ans
)更好的结果。 - 它使用回溯法来探索所有可能的路径。
-
主函数 (
main
):- 读取输入数据,包括测试用例的数量
t
。 - 对于每个测试用例:读取地图尺寸、时间限制和宝石数量。读取宝石价值并初始化地图。从起始点、出口点以及每个宝石的位置执行BFS来计算最短路径。初始化
vis
并从起始点开始进行DFS以找到最优路径。输出当前测试用例的结果。
- 读取输入数据,包括测试用例的数量
核心思想是预先计算出所有点对(起点、宝石、出口)之间的最短距离,使用BFS,然后使用DFS探索所有可能的宝石组合,这些组合可以在时间限制内被收集。DFS函数跟踪收集的总价值和所花费的时间,确保解决方案不超过时间限制。最终答案是在这些约束条件下可以达到的最高总价值。
HDU1045——Fire Net
题目描述
运行代码
#include <iostream>
#include <cstring>
#include <cstdio>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
#define N 6
using namespace std;
char Map[N][N];
int flag[N];
int row[N][N], col[N][N], r[N], c[N];
int cnt_col, cnt_row;
bool path[N][N];
int DFS(int x) {
for (int i = 0; i < cnt_col; i++) {
if (!path[x][i] || flag[i])
continue;
flag[i] = 1;
if (c[i] == -1 || DFS(c[i])) {
c[i] = x;
r[x] = i;
return 1;
}
}
return 0;
}
void Hungarian() {
int ans = 0;
memset(r, -1, sizeof(r));
memset(c, -1, sizeof(c));
for (int i = 0; i < cnt_row; i++) {
if (r[i] == -1) {
memset(flag, 0, sizeof(flag));
ans += DFS(i);
}
}
cout << ans << endl;
}
int main() {
int n;
while (scanf_s("%d%*c", &n) != EOF && n) {
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
Map[i][j] = getchar();
}
getchar();
}
memset(row, -1, sizeof(row));
memset(col, -1, sizeof(col));
cnt_row = cnt_col = 0;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < n; ++j) {
if (Map[i][j] == '.' && row[i][j] == -1) {
for (int k = j; Map[i][k] == '.' && k < n; k++)
row[i][k] = cnt_row;
cnt_row++;
}
if (Map[j][i] == '.' && col[j][i] == -1) {
for (int k = j; Map[k][i] == '.' && k < n; k++)
col[k][i] = cnt_col;
cnt_col++;
}
}
}
memset(path, false, sizeof(path));
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
if (Map[i][j] == '.')
path[row[i][j]][col[i][j]] = true;
Hungarian();
}
return 0;
}
代码思路
-
读取输入: 首先,程序读取一个整数
n
,表示棋盘的大小n x n
。接下来,它读取棋盘的状态,其中.
表示空位,而其他字符则表示障碍物或不可通行的位置。 -
构建行和列的索引: 接下来,程序遍历整个棋盘,对于每一行和每一列中的连续的
.
,它会分配一个索引,这将用于后续的匹配过程。例如,如果一行中有两个不相连的.
序列,它们将分别被赋予不同的索引。 -
构建匹配图: 程序创建一个布尔矩阵
path
,其中path[i][j]
为真表示第i
个行索引和第j
个列索引之间存在一个可以匹配的空位(即棋盘上的一个.
)。这是通过遍历棋盘,如果遇到一个空位,则标记相应的行和列的索引间存在连接。 -
匈牙利算法实现: 使用匈牙利算法来找出最大匹配。匈牙利算法是一种在二分图中找到最大匹配的算法,这里的二分图是由行索引和列索引构成的。算法通过一系列深度优先搜索(DFS)尝试从行索引出发找到未匹配的列索引,形成匹配对。
-
执行匈牙利算法: 在
Hungarian
函数中,首先初始化r
和c
数组来存储行和列的匹配情况。然后,对于每一个行索引,如果它没有匹配,就执行DFS
函数来尝试找到一个匹配的列索引。DFS
函数递归地尝试匹配,并返回一个布尔值表示是否成功找到匹配。如果成功,就更新r
和c
数组来记录新的匹配关系,并增加匹配计数器ans
。 -
输出结果: 最后,输出
ans
作为最长的不相交的行与列匹配的数量。
HDU1046——Gridland
题目描述
运行代码
#include <iostream>
#include<iomanip>
using namespace std;
int main() {
int n, a, b, i = 0;
float temp = 0;
cin >> n;
while (n--) {
i++;
cin >> a >> b;
temp = a * b;
if (a % 2 != 0 && b % 2 != 0)
temp = temp - 1 + 1.41;
cout << "Scenario #" << i << ":" << endl;
cout << fixed << setprecision(2) << temp << endl << endl;
}
return 0;
}
代码思路
-
初始化变量:
n
:存储用户输入的循环次数,也就是要处理多少组数据。a
和b
:存储每组数据中的两个整数。i
:用于追踪当前处理的是哪一组数据,以便在输出中使用。temp
:用于存储每组数据的计算结果,类型为float
,因为计算过程中可能会出现小数。
-
读取循环次数: 用户首先输入一个整数
n
,表示之后会有n
组数据需要处理。 -
循环处理数据:
- 使用
while
循环,循环次数由n
决定。 - 在每次循环开始时,
i
增加1,用于标识当前处理的是第几组数据。 - 接收用户输入的两个整数
a
和b
。 - 计算
a
和b
的乘积,并将结果存储在temp
中。
- 使用
-
条件判断:检查
a
和b
是否都是奇数(即a % 2 != 0
且b % 2 != 0
)。如果是,那么在乘积的基础上减去1并加上1.41。 -
输出结果:
- 在输出之前,先使用
cout
打印出当前处理的是哪一组数据,格式为:"Scenario #" + 当前组数。 - 使用
fixed
和setprecision(2)
来设置输出的浮点数格式,保留两位小数。 - 打印计算后的
temp
值。 - 每组数据输出后,再输出两个换行符,使输出更加清晰易读。
- 在输出之前,先使用
-
结束:循环结束后,程序正常退出,返回0。