第2部份的4道题开始啦!
Sortint It All Out,我用的是Floyd算法去判断有没有inconsistency(检查是否有自己相连的情况),然后统计已经得到的点的出入度(Floyed后,满足题意时出入度正好是0,1,2,...,n-1)可以去确定是否determine。不过这个算法貌似十分低效,正解应该是Topological Sorting……
#include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <ctime> #include <fstream> using namespace std; const long double pi = 3.1415926535898; int n; bool mat[26][26]; struct A { int i, n; }a[26]; bool cmp(A a, A b) { return a.n < b.n; } int check(string *str) { bool tmpmat[26][26]; memcpy(tmpmat, mat, sizeof(tmpmat)); for(int k = 0; k < n; k++) for(int i = 0; i < n; i++) for(int j = 0; j < n; j++) tmpmat[i][j] |= tmpmat[i][k] && tmpmat[k][j]; for(int i = 0; i < n; i++) if(tmpmat[i][i]) return -1; memset(a, 0, sizeof(a)); for(int i = 0; i < n; i++) { a[i].i = i; for(int j = 0; j < n; j++) if(tmpmat[i][j]) a[j].n++; } sort(a, a + n, cmp); for(int i = 0; i < n; i++) { if(a[i].n != i) return 0; *str += a[i].i + 'A'; } return 1; } int main() { int m; cin >> n >> m; while(n || m) { bool b = 0; memset(mat, 0, sizeof(mat)); int M = m; while(m--) { char first, second; getchar(); scanf("%c<%c", &first, &second); if(b) continue; mat[first - 'A'][second - 'A'] = 1; string str; int line = check(&str); if(line == 1) cout << "Sorted sequence determined after " << M - m << " relations: " << str << '.' << endl; if(line == -1) cout << "Inconsistency found after " << M - m << " relations." << endl; b = line; } if(!b) cout << "Sorted sequence cannot be determined." << endl; cin >> n >> m; } return 0; }
Space Station Shielding惭愧地搞定。一开始用DFS搜里面的grid cubes,后来发现没办法区分里面和外面,看了别人的代码后发现应该搜不属于这个n*m*k grid的外面一层,这样就可以判定里外了。一开始仍然用刚开始写的DFS,发现SF,测试了60 60 60 1 0这个数据发现的确是DFS太深Stack Overflow了,于是通过vector改用BFS,需要判断已加入vector的元素(已加入则一定不能再加入),用一个62*62*62的数组保存加入情况(本来使用find判断,后来发现自定义数据结构似乎无法用find?)。只要想到了以上这些写起来就比较方便:遇到ACM就加一个面,遇到非ACM的有效cube就不重复地加入vector,无效的情况就跳出。
#include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <ctime> #include <fstream> using namespace std; const long double pi = 3.1415926535898; const int di[6] = {1, -1, 0, 0, 0, 0}; const int dj[6] = {0, 0, 1, -1, 0, 0}; const int dk[6] = {0, 0, 0, 0, 1, -1}; struct grids { int i, j, k; }grid; int n, m, k, ACM[60][60][60], cnt; bool b[238328]; vector<grids> myvector; void bfs(int length, int width, int height) { for(int l = 0; l < 6; l++) { int ni = length + di[l], nj = width + dj[l], nk = height + dk[l]; if(ni < -1 || ni > n || nj < -1 || nj > m || nk < -1 || nk > k) continue; if(ni >= 0 && ni < n && nj >= 0 && nj < m && nk >= 0 && nk < k && ACM[ni][nj][nk]) { cnt++; continue; } if(!b[(ni + 1) + (nj + 1) * 62 + (nk + 1) * 62 * 62]) { grid.i = ni; grid.j = nj; grid.k = nk; myvector.push_back(grid); b[(grid.i + 1) + (grid.j + 1) * 62 + (grid.k + 1) * 62 * 62] = 1; } } } int main() { int l; while(cin >> n >> m >> k >> l, n || m || k || l) { memset(ACM, 0, sizeof(ACM)); cnt = 0; memset(b, 0, sizeof(b)); myvector.clear(); for(int i = 0; i < l; i++) { int cube; cin >> cube; int height = cube / (n * m); cube %= n * m; int length = cube % n, width = cube / n; ACM[length][width][height] = 1; } grid.i = grid.j = grid.k = -1; myvector.push_back(grid); b[(grid.i + 1) + (grid.j + 1) * 62 + (grid.k + 1) * 62 * 62] = 1; for(int i = 0; i < int(myvector.size()); i++) bfs(myvector[i].i, myvector[i].j, myvector[i].k); cout << "The number of faces needing shielding is " << cnt << '.' << endl; } return 0; }
Square Ice搞定!很简单的模拟题(涉及到一点点的数列),固定m后,实际上除了'-'和'|'其他的字符全部都固定了(数列推一下即可),确定'-'和'|':+-1的情况很容易,0的情况只要看上面的或左边的'H'有没有被使用(用一个bool数组储存是用情况),没有就是用,有就是用下面的或右边的'H'即可(之所以是这样的顺序是因为推的过程是从上到下、从左到右,如果推的过程相反,那么前面的判断也应该相反)。最后在192上提交30ms,是最慢的,但不是很清楚哪里慢了……
#include <vector> #include <list> #include <map> #include <set> #include <deque> #include <queue> #include <stack> #include <bitset> #include <algorithm> #include <functional> #include <numeric> #include <utility> #include <sstream> #include <iostream> #include <iomanip> #include <cstdio> #include <cmath> #include <cstdlib> #include <cctype> #include <string> #include <cstring> #include <ctime> #include <fstream> using namespace std; const long double pi = 3.1415926535898; int main() { int n = 1; int m, ASM[11][11]; char ice[43][48]; bool H[43][48]; while(cin >> m, m) { if(n != 1) cout << endl; cout << "Case " << n++ << ':' << endl << endl; int length = 4 * m + 3, width = 4 * m - 1; for(int i = 0; i < m; i++) for(int j = 0; j < m; j++) cin >> ASM[i][j]; for(int i = 0; i < width; i++) for(int j = 0; j < length; j++) if(i == 0 || i == width - 1 || j == 0 || j == length - 1) ice[i][j] = '*'; else ice[i][j] = ' '; for(int i = 0; i < 4 * m - 1; i++) ice[i][4 * m + 3] = 0; for(int i = 1; i < width; i += 4) for(int j = 3; j < length; j += 4) ice[i][j] = 'O'; for(int i = 1, tag = -1; i < width; i += 2, tag = -tag) for(int j = 2 + tag; j < length; j += 4) ice[i][j] = 'H'; memset(H, 0, sizeof(H)); for(int i = 0; i < m; i++) for(int j = 0; j < m; j++) { int l = 4 * j + 3, w = 4 * i + 1; if(ASM[i][j] == 1) { ice[w][l + 1] = ice[w][l - 1] = '-'; H[w][l + 2] = H[w][l - 2] = 1; } if(ASM[i][j] == -1) { ice[w + 1][l] = ice[w - 1][l] = '|'; H[w + 2][l] = H[w - 2][l] = 1; } if(!ASM[i][j]) { if(l >= 2 && !H[w][l - 2]) { ice[w][l - 1] = '-'; H[w][l - 2] = 1; } else { ice[w][l + 1] = '-'; H[w][l + 2] = 1; } if(w >= 2 && !H[w - 2][l]) { ice[w - 1][l] = '|'; H[w - 2][l] = 1; } else { ice[w + 1][l] = '|'; H[w + 2][l] = 1; } } } for(int i = 0; i < width; i++) puts(ice[i]); } return 0; }