zoukankan      html  css  js  c++  java
  • 算法竞赛入门经典 第六章



    • [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] 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;
      }
      

    • [x] UVA10129 单词 Play on Words

      判断有向图是否存在欧拉路径,只要判断以下两点即可:

      1. 最多存在2个结点的出度不等于入度,且其中一个点出度-入度=1,作为起点,另一个点出度-入度=-1,作为终点。
      2. 图是连通图(只要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;
      }
      






  • 相关阅读:
    笔记本硬盘接口SATA, PATA
    dB和dBm的区别
    SQL Server 存储过程分页方案比较
    SQL Server 输出参数OUTPUT
    安装iis5.1时找不到zClientm.exe的解决方法
    mac os x 10.5.8不通本网段
    SQL Server 存储过程分页大全(2005,2000)
    硬盘保修查询网站明细清单希捷硬盘保修查询西数硬盘保修查
    如何让SWT的窗口置顶(总在最上面)?
    ASP.NET(三) Web开发——常用服务器控件
  • 原文地址:https://www.cnblogs.com/streamazure/p/12656665.html
Copyright © 2011-2022 走看看