目录
1. BFS试炼之微博转发
2. DFS试炼之不同路径数
3. 并查集试炼之合并集合
4. 堆排序
5. 厦大GPA
6. 消防安全指挥问题
7. 铺设光纤问题
8. CCF A会报告
9. 商店 (挑战题)
Tag:bfs
存储:邻接表
思路:有搜索层数限制,用dist数组记录层数,超出要求则continue
#include
#include
#include
#include
#include
using namespace std;
const int N = 1005;
int n, l;
int e[N], ne[N], h[N], idx, dist[N];
bool st[N];
queue q;
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
int bfs(int x) {
memset(st, 0, sizeof st);
memset(dist, 0, sizeof dist);
q.push(x);
st[x] = true;
int cnt = 0;
while (q.size()) {
auto t = q.front();
q.pop();
for (int i = h[t]; i != -1; i = ne[i]) {
int j = e[i]; //cout << j << endl;
if (st[j]) continue;
dist[j] = dist[t] + 1;
if (dist[j] > l) continue;
++ cnt;
q.push(j);
st[j] = true;
}
}
return cnt;
}
int main() {
memset(h, -1, sizeof h);
cin >> n >> l;
for (int i = 1; i <= n; ++ i) {
int num, x;
cin >> num;
for (int j = 0; j < num; ++ j) {
cin >> x;
add(x, i);
// cout << x << ' ' << i << endl;
}
}
int t;
cin >> t;
while (t --) {
int x;
cin >> x;
cout << bfs(x) << endl;
}
return 0;
}
Tag:dfs,字符串哈希
思路:以每个点为起点dfs搜索。用字符串哈希记录不重复路径数。
#include
#include
#include
#include
#include
using namespace std;
const int N = 7;
char g[N][N];
bool st[N][N];
int n, m, k, ans;
unordered_set s;
char str[10];
void dfs(int x, int y, int u) {
if (u > k) {
//cout << str << endl;
if (!s.count(str)) {
s.insert(str);
++ ans;
}
return;
}
st[x][y] = true;
str[u] = g[x][y];
//cout << u << ' ' << str << endl;
int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1};
for (int i = 0; i < 4; ++ i) {
int xx = x + dx[i], yy = y + dy[i];
if (xx < 0 || xx >= n || yy < 0 || yy >= m) continue;
dfs(xx, yy, u + 1);
}
}
int main() {
cin >> n >> m >> k;
for (int i = 0; i < n; ++ i)
for (int j = 0; j < m; ++ j)
cin >> g[i][j];
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < m; ++ j) {
memset(st, 0, sizeof st);
dfs(i, j, 0);
}
}
cout << ans << endl;
return 0;
}
Tag: 并查集
思路:模板题
#include
#include
#include
#include
using namespace std;
const int N = 1e5 + 5;
int p[N];
int n, m;
int find(int x) {
return x == p[x] ? x : p[x] = find(p[x]);
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++ i) p[i] = i;
while (m --) {
char c;
int x, y;
cin >> c >> x >> y;
if (c == 'M') {
if (find(x) != find(y)) p[find(x)] = find(y);
} else {
if (find(x) == find(y)) puts("Yes");
else puts("No");
}
}
return 0;
}
略。用sort混过去了。
Tag:分组背包、(贪心)
思路:
绩点是价值,分数是体积,总分是容积。
分组背包问题,4组,每组可以取一个分数。
(前置处理写麻烦了,贪心只用每个档的最低分数数据就可以了)
#include
#include
#include
#include
using namespace std;
//绩点是价值 分数是体积 总分是容积
//分组背包问题 4组 每组可以取一个分数
const int N = 405;
int v[N], w[N];
int f[N];
void init() {
for (int i = 1, s = 0; s <= 100;) {
switch (s) {
case 0:
for (; s <= 59; ++i, ++s) v[i] = s, w[i] = 0;
break;
case 60:
for (; s <= 63; ++i, ++s) v[i] = s, w[i] = 10;
break;
case 64:
for (; s <= 67; ++i, ++s) v[i] = s, w[i] = 17;
break;
case 68:
for (; s <= 71; ++i, ++s) v[i] = s, w[i] = 20;
break;
case 72:
for (; s <= 74; ++i, ++s) v[i] = s, w[i] = 23;
break;
case 75:
for (; s <= 77; ++i, ++s) v[i] = s, w[i] = 27;
break;
case 78:
for (; s <= 80; ++i, ++s) v[i] = s, w[i] = 30;
break;
case 81:
for (; s <= 84; ++i, ++s) v[i] = s, w[i] = 33;
break;
case 85:
for (; s <= 89; ++i, ++s) v[i] = s, w[i] = 37;
break;
case 90:
for (; s <= 100; ++i, ++s) v[i] = s, w[i] = 40;
break;
}
}
}
int main() {
init();
//for(int i=1; i<=101; ++ i) printf("%d %d\n", v[i], w[i]);
int m;
while (cin >> m) {
memset(f, 0, sizeof f);
for (int i = 1; i <= 4; ++ i) {
for (int j = m; j >= 0; -- j) {
for (int k = 1; k <= 101; ++ k)
if (v[k] <= j)
f[j] = max(f[j], f[j - v[k]] + w[k]);
//cout << f[i][j] << endl;
}
}
double res = f[m] / 10.0;
//cout << res << endl;
printf("%.1f\n", res);
}
return 0;
}
Tag:dijkstra
思路:对消防队在的位置为起点dijkstra,比较取最短。
#include
#include
#include
#include
using namespace std;
const int N = 1005;
int xfd[N];
int n, m, p, q;
int g[N][N], dist[N];
bool st[N];
int dijkstra(int x) {
memset(dist, 0x3f, sizeof dist);
memset(st, 0, sizeof st);
dist[x] = 0;
//cout << m << endl;
for (int i = 0; i < m; ++ i) {
int t = -1, dis = 0x3f3f3f3f;
for (int j = 1; j <= m; ++ j) {
if (!st[j] && (t == -1 || dist[j] < dis)) {
t = j;
dis = dist[j];
}
}
//cout << t << endl;
st[t] = true;
if (t == q) return dist[q];
for (int i = 1; i <= m; ++ i) dist[i] = min(dist[i], dist[t] + g[t][i]);
}
return 0x3f3f3f3f;
}
int main() {
int t;
cin >> t;
while (t --) {
cin >> n >> m >> p >> q;
memset(g, 0x3f, sizeof g);
for (int i = 0; i < n; ++i) cin >> xfd[i];
while (p --) {
int a, b, w;
cin >> a >> b >> w;
g[a][b] = g[b][a]= min(g[a][b], w);
}
int ans = 0x3f3f3f3f;
for (int i = 0; i < n; ++ i) {//cout <
Tag:prim
思路:模板题。纳入未标记的离现有的一团点距离最近的点。dist存的是到当前这团点的距离。
#include
#include
#include
#include
using namespace std;
const int N = 105;
int g[N][N], dist[N];
int n, ans;
bool st[N];
void prim() {
memset(dist, 0x3f, sizeof dist);
dist[1] = 0;
for (int i = 0; i < n; ++ i) {
int dis = 0x3f3f3f3f, t;
for (int j = 1; j <= n; ++ j) {
if (!st[j] && dist[j] < dis) {
dis = dist[j];
t = j;
}
}
st[t] = true;
ans += dist[t];
for (int i = 1; i <= n; ++i) dist[i] = min(dist[i], g[t][i]);
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; ++ i)
for (int j = 1; j <= n; ++ j)
cin >> g[i][j];
prim();
cout << ans << endl;
return 0;
}
Tag:多重背包
思路:模板题。除种类体积外,再循环每个品类的个数。注意判是否小于等于容积。
拓展:如果s[]的范围增大,则可以考虑二进制打包优化。
#include
#include
#include
#include
using namespace std;
const int N = 6005;
int v[N], w[N], s[N];
int n, m;
int f[N];
int main() {
cin >> n >> m;
for (int i = 1; i <= n; ++ i) {
cin >> v[i] >> w[i] >> s[i];
}
for (int i = 1; i <= n; ++ i) {
for (int j = m; j >= v[i]; -- j) {
for (int k = 1; k <= s[i]; ++ k) {
if (k * v[i] <= j)
f[j] = max(f[j], f[j - k * v[i]] + k * w[i]);
}
}
}
cout << f[m] << endl;
return 0;
}
Tag:贪心
存储:优先队列小根堆
思路:
贪心:为了满足尽可能多的预订单,每次应优先处理商品数少的订单
又因为当天的货物只可以被当天的订单和后续的订单消耗,所以可以倒序处理数据
核心:用当前的供应量增序处理队列中的剩余订单
#include
#include
#include
#include
#include
using namespace std;
#define out first
#define index second
typedef pair PII;
const int N = 3e5 + 5;
priority_queue, greater > q;
int in[N], out[N];
int n, res;
int main() {
cin >> n;
for (int i = 1; i <= n; ++ i) cin >> in[i] >> out[i];
for(int i=n; i; --i){
int cur = in[i];
q.push({out[i], i});
while(q.size()){
auto t = q.top();
q.pop();
int csm = min(t.out, cur);
cur -= csm;
t.out -= csm;
if(t.out == 0) ++ res;
else q.push(t);
if(cur == 0) break;
}
}
cout << res << endl;
return 0;
}