这次上午主要是熟悉环境,顺便讲解了周四的选拔赛的题目的方法,发现好多是BRUTE FORCE,但自己没有写出来!
其次就是看到了老队员,像杨骞,虽然要备战考研,还是来了,这感情~
原来上周纠结的一道Radar的题目要用Dancing Links去解决俗称DLX,努力去攻克这个算法。
下午的任务竟然是重做周四的题目……虽然有点不情愿,但增加编程的熟练度嘛,还是做啦!
很纠结的是拿到Devil May Cry,弄了半天,发现数据有问题。。。。其次组队那道题目却用搜索,并查集可以优化,但不是主流,很好,能把8个题目在下午的时间里AC掉,也算是一个小小的进步,否创有些题目可能就过去了,成为遗憾了!
A题是一个拓扑排序,没有人被监视的可以攻击,相当于入读为0的点可以去掉;
B题是一个字符串匹配,尽量选择靠前的匹配,只要维护两个指针就可以了;
C题是比较好的题目,有3N个人(N<=4),给出希望与不愿的关系,问是否存在组队成功(满足所有人的要求)的方案
太容易想到并查集了,人数多余3人可以判断,但对于“不愿”的情况就难以判断了;
鉴于数据量不大,可以用BRUTE FORCE,效率是O(N^(3N)),由于题目数据比较弱,“意愿”比较少,如果多了,朴素的方法估计就不行了!
#include <stdio.h> #include <string.h> const int maxlen = 10000; int n, m, steam, i; int tot[4], team[12]; int a[maxlen], b[maxlen], c[maxlen]; bool dfs(int dep) { if (dep == n) { for (i = 0; i < m; i++) if (c[i] == 0 && team[a[i]] == team[b[i]] || c[i] == 1 && team[a[i]] != team[b[i]]) return false; return true; } for (int k = 0; k < steam; k++) if (tot[k] < 3) { team[dep] = k; tot[k]++; bool flag; flag = dfs(dep+1); if (flag) return true; tot[k]--; } return false; } int main() { while (scanf("%d %d", &n, &m) == 2) { memset(tot,0,sizeof(tot)); steam = n/3; for (i = 0; i < m; i++) scanf("%d %d %d", &a[i], &b[i], &c[i]); if (dfs(0)) printf("Yes/n"); else printf("No/n"); } return 0; }
D题属于变种的BFS:地块会周期性地出现、消失,求出从左下角到右上角的最少时间;
题目中的描述比较长,所以要训练顽强的读题能力;刚开始没有读懂题目,但是根据题目中的数据推测了行走的方式,结果证明是对的(虽然历经波折~~~)。
这道题目的思想还是很好的:
1)建图:根据周期性,最多有T张图,所以预先处理出这T张图,如果时间超出了T,那么只要对T取模即可;
2)判重:由于同一幅图中走过的点不可能再走,所以走过就可以把该点取消掉;
#include <stdio.h> #include <string.h> const int dx[5] = {0,-1,0,1,0}, dy[5] = {1,0,-1,0,0}; char c[20]; int map[10][10][10], vis[2][10][10]; int main() { freopen("d.in", "r", stdin); freopen("d.out", "w", stdout); int n, m, t; while (scanf("%d %d %d/n", &n, &m, &t) == 3) { int i, j, k, tt; for (i = 0; i < n; i++) { scanf("%s", c); for (j = 0; j < m; j++) map[0][i][j] = (t-(c[j]-'0'))%t; } for (tt = 1; tt < t; tt++) { for (i = 0; i < n; i++) for (j = 0; j < m; j++) map[tt][i][j] = (map[tt-1][i][j]+1)%t; } for (tt = 0; tt < t; tt++) { printf("Time:%d/n", tt); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) if (map[tt][i][j] < t/2) printf("1"); else printf("0"); printf("/n"); } } tt = 0; int state = 0, zero; bool find = false; memset(vis,0,sizeof(vis)); do { state = 1-state; zero = 0; for (i = 0; i < n; i++) for (j = 0; j < m; j++) vis[state][i][j] = 0; if (map[tt%t][n-1][0] < t/2) { vis[state][n-1][0] = 1; zero = 1; map[tt%t][n-1][0] = t; //printf("%d/n", tt); } for (i = 0; i < n; i++) for (j = 0; j <m; j++) if (vis[1-state][i][j]) { for (k = 0; k < 5; k++) { int nx = dx[k]+i, ny = dy[k]+j; if (nx < 0 || ny < 0 || nx >= n || ny >= m || map[tt%t][nx][ny] >= t/2) continue; map[tt%t][nx][ny] = t; vis[state][nx][ny] = 1; zero = 1; //printf("%d:%d %d/n", tt-1, nx, ny); } } if (vis[state][0][m-1]) { find = true; break; } tt++; } while (zero || tt <= t); if (find) printf("%d/n", tt); else printf("Mission Impossible!/n"); } return 0; }
E题判断前缀后缀,有常量字符串处理会简单,但要注意处理完前缀后,要及时清除;
周四过了的,今天竟然没过~~发现是一个BOOL变量初值错了;
F题当时想着用随机,后来也是BRUTE FORCE
大意:有N(<=6)个猎人和M(<=8)个财产,不同财产对不同人的价值不一样,求出把这M个财产分完后猎人中得到的价值的极差。
由于1个物品只能由1个归属人,而一个猎人有可能有多个物品,所以在DFS时以物品为阶段。
#include <stdio.h> #include <string.h> const int max_t = 10, max_h = 10; int map[max_h][max_t], tot[max_h], storep[max_t], p[max_t]; int hunter, treasure, best; void dfs(int dep){ if (dep == treasure) { int max = 0, min = 1 << 30; for (int k = 0; k < hunter; k++) { if (tot[k] < min) min = tot[k]; if (tot[k] > max) max = tot[k]; } if (max - min < best) { best = max - min; memcpy(storep, p, sizeof(p)); } return ; } for (int k = 0; k < hunter; k++) { p[dep] = k; tot[k] += map[k][dep]; dfs(dep+1); tot[k] -= map[k][dep]; } } int main() { freopen("spit.in", "r", stdin); freopen("spit.out", "w", stdout); char c[10]; bool first = true; while (scanf("%s", c) == 1) { if (!first) printf("/n"); else first = false; scanf("%d/n%d/n", &treasure, &hunter); int i, j; for (i = 0; i < hunter; i++) for (j = 0; j < treasure; j++) scanf("%d", &map[i][j]); memset(tot,0,sizeof(tot)); best = 1 << 30; dfs(0); for (i = 0; i < hunter; i++) { int sum = 0; for (j = 0; j < treasure; j++) if (storep[j] == i) { printf("%d ", j+1); sum += map[i][j]; } printf("%d/n", sum); } //printf("/n"); scanf("%s", c); } }
G题是简单的高精度乘方;
H题是错排;
f[n] = (n-1) (f[n-1]+f[n-2])
总体感觉不是太难,没有太难的算法,只要练习熟练度和CODING ABILITY