- [x] UVA514 铁轨 Rails
-
[x] UVA11988 破损的键盘 Broken Keyboard (a.k.a. Beiju Text)
Home键按下,光标移到该行开头;End键按下,光标移到该行结尾。
设输入字符串为s[1~i],则用Next[i]表示当前显示屏中s[i]右边的字符在s中的下标
例如,设Next[1]=2,Next[2]=4,则在实际显示中顺序如下:s[1]s[2]s[4]
本题用数组模拟链表,就可以灵活地储存各字符之间的相对位置。假设字符串s的最前面存在一个虚拟的s[0],则Next[0]表示显示屏中最左边的字符。再用cur储存光标位置,当前光标位于s[cur]的右边。当cur=0时,光标在显示屏的最左边。再用变量last表示显示屏最后一个字符s[last]。
$color{green}{UVa11988-代码}$
#include<iostream> #include<algorithm> #include<cstring> #include<map> #include<stack> #include<queue> using namespace std; const int maxn = 100000 + 5; int last, cur, Next[maxn]; char s[maxn]; int main() { while (cin >> s + 1) {//把s[0]空出来 int n = strlen(s + 1); last = cur = 0; Next[0] = 0; for (int i = 1;i <= n;i++) { char ch = s[i]; if (ch == '[') cur = 0;//光标跳到最左边 else if (ch == ']') cur = last;//光标跳到最右边 else { Next[i] = Next[cur];//s[i]的右边字符的下标是光标所指右边字符的下标 Next[cur] = i;//光标所指右边字符下标应该是[右边字符的下标 if (cur == last) last = i;//更新最后一个字符的下标 cur = i;//移动光标 } } //for(int i=0;i<=last;i++) //cout << "Next[" << i << "]=" << Next[i] << endl; for (int i = Next[0];i != 0;i = Next[i]) { cout << s[i]; } cout << endl; } return 0; }
-
[x] UVA12657 移动盒子 Boxes in a Line
模拟双向链表,用一个Link函数实现两结点间的连接
void Link(int L,int R){ right[L]=R;left[R]=L; //左边的结点伸出一条链连向右边 //右边的结点伸出一条链连向左边 }
注意Link操作的先后顺序:Link(X,Y)不会影响Right[Y]
$color{green}{UVa12657-代码} $
#include<iostream> #include<algorithm> #include<cstring> #include<map> #include<stack> #include<queue> #include<cstdio> using namespace std; int Right[1000000 + 10]; int Left[1000000 + 10]; int n, m; void Link(int L, int R) { Right[L] = R; Left[R] = L; } int main() { //FILE* stream1; //freopen_s(&stream1, "input.txt", "r", stdin); //freopen_s(&stream1, "output.txt", "w", stdout); int kase = 0; while (cin >> n >> m) { for (int i = 1;i <= n;i++) { Left[i] = i - 1; Right[i] = (i + 1) % (n + 1); //Right[n]=0; } Right[0] = 1; Left[0] = n; int op, X, Y, inv = 0; while (m--) { cin >> op; if (op == 4) inv = !inv; else { cin >> X >> Y; if (op == 3 && Right[Y] == X) swap(X, Y); if (inv && op != 3) op = 3 - op;//1变2,2变1 if (op == 1 && X == Left[Y]) continue; if (op == 2 && X == Right[Y]) continue; int LX = Left[X], RX = Right[X], LY = Left[Y], RY = Right[Y]; //一定要先储存再重新链接,否则会在链接过程中相互影响 if (op == 1) { Link(LX, RX); Link(LY, X); Link(X, Y); } else if (op == 2) { Link(LX, RX); Link(Y, X); Link(X, RY); } else if (op == 3) { if (Right[X] == Y) { Link(LX, Y); Link(Y, X); Link(X, RY); } else { Link(LX, Y); Link(Y, RX); Link(LY, X); Link(X, RY); } } } } int b = 0; long long ans = 0; for (int i = 1;i <= n;i++) { b = Right[b]; if (i % 2 == 1) ans += b; } //如果是奇数个盒子,最后的翻转不影响结果 //但偶数个盒子就会影响 if (inv && n % 2 == 0) ans = (long long)n * (n + 1) / 2 - ans; printf("Case %d: %lld ", ++kase, ans); } return 0; }
- [x] UVA548 树 Tree
-
[x] UVA10305 给任务排序 Ordering Tasks
拓扑排序,注意在DFS过程中判断给定图是否为DAG
$color{green}{UVa10305-代码}$
#include<iostream> #include<algorithm> #include<cstring> #include<map> #include<stack> #include<queue> #include<cstdio> using namespace std; int E[1000 + 10][1000 + 10]; int vis[100 + 10]; int topo[100 + 10]; int n, m, pos; bool dfs(int V) { vis[V] = -1; for (int u = 1;u <= n;u++) { if (E[V][u]) { if (vis[u] < 0) return false;//存在有向环 else if (!vis[u] && !dfs(u)) return false; //没访问过的新结点进行访问,但过程中出现有向环 } } vis[V] = 1; topo[pos] = V; pos--; return true; } bool toposort() { for (int u = 1;u <= n;u++) { if (!vis[u] && !dfs(u))return false; } return true; } int main() { while (cin >> n >> m) { if (!n && !m) break; memset(E, 0, sizeof(E)); memset(topo, 0, sizeof(topo)); memset(vis, 0, sizeof(vis)); pos = n; for (int i = 1;i <= m;i++) { int a, b; cin >> a >> b; E[a][b] = 1; } if (toposort()) { cout << topo[1]; for (int i = 2;i <= n;i++) cout << " " << topo[i]; cout << endl; } } return 0; }
-
判断有向图是否存在欧拉路径,只要判断以下两点即可:
- 最多存在2个结点的出度不等于入度,且其中一个点出度-入度=1,作为起点,另一个点出度-入度=-1,作为终点。
- 图是连通图(只要DFS一次就能访问所有的结点)。
$color{green}{UVa10129-代码}$
#include<iostream> #include<map> #include<cstring> using namespace std; string words[100000 + 10]; int E[2000][2000],n,cnt,pass; struct Node { int in = 0, out = 0; bool vis = false; }node[30]; void dfs(int u) { node[u].vis = true; pass++; for (int i = 1;i <= cnt;i++) if (!node[i].vis && E[u][i]) dfs(i); } int main() { //FILE* stream1; //freopen_s(&stream1, "input.txt", "r", stdin); //freopen_s(&stream1, "output.txt", "w", stdout); int t;cin >> t; while (t--) { memset(E, 0, sizeof(E)); memset(node, 0, sizeof(node)); map<char, int> m; cnt = 0; cin >> n; for (int i = 1;i <= n;i++) { cin >> words[i]; char begin = words[i][0], end = words[i][words[i].length() - 1]; if (!m.count(begin)) m[begin] = ++cnt; if (!m.count(end)) m[end] = ++cnt; E[m[begin]][m[end]] = 1; node[m[begin]].out++; node[m[end]].in++; } int start = 0, end = 0, ok = 1, si; for (int i = 1;i <= cnt;i++) { int k = node[i].in - node[i].out; if (k == 0) continue; else if (k == 1) end++; else if (k == -1) {start++;si = i;} else { ok = 0;break; } } if (ok && start == end && start <= 1) ok = 1; else ok = 0; pass = 0; if (ok && start == 0) dfs(1); else if (ok && start == 1) dfs(si); if (pass < cnt) ok = 0; if (!ok) cout << "The door cannot be opened." << endl; else cout << "Ordering is possible." << endl; } return 0; }