洛谷P1042、P2670 自我总结

P1042

杂记:

  • oj刷题使用STL会发现时间明显增加。在空间复杂度上看,法一平均更占优势,时间上由于频繁地构造和析构,繁费了大量的时间,本来时间上相当。
  • 猜想:将更多地操作挪到循环次数低的循环体中,说不定可以降低时间消耗。
  • 另外,使用vector的时候预先reserve,可以大大减小大量数据导致的拷贝开销
#include <bits/stdc++.h>
using namespace std;

int main()
{
#ifdef _LOC_
   freopen("1.in", "r", stdin);
   freopen("1.out", "w", stdout);
#endif
   char c;
   int a[4] = {};
   vector<pair<int, int>> ans1, ans2;
   while (cin.get(c))//O(n) and average 4 branches.
   {
      if (c == 'W')
         a[0]++, a[2]++;
      else if (c == 'L')
         a[1]++, a[3]++;
      else if (c == 'E')
      {
         ans1.push_back(make_pair(a[0], a[1]));
         ans2.push_back(make_pair(a[2], a[3]));
         break;
      }
      if ((a[0] >= 11 || a[1] >= 11) && abs(a[0] - a[1]) >= 2)
      {
         ans1.push_back(make_pair(a[0], a[1]));
         a[0] = a[1] = 0;
      }
      if ((a[2] >= 21 || a[3] >= 21) && abs(a[2] - a[3]) >= 2)
      {
         ans2.push_back(make_pair(a[2], a[3]));
         a[2] = a[3] = 0;
      }
   }
   for (auto it : ans1)//O(n)/20
      cout << it.first << ':' << it.second << endl;
   cout << endl;
   for (auto it: ans2)//O(n)/40
      cout << it.first << ':' << it.second << endl;
   fclose(stdout);
   return 0;
}

#include <bits/stdc++.h>
using namespace std;
int cntl, cntw;
int main()
{
    char s[62505], tmp;
    int i;
    for (i = 1; ; i++)//O(n)
    {
        cin >> tmp;
        if (tmp == 'E')
            break;
        s[i] = tmp;
    }
    for (int j = 1; j < i; j++)//O(n) 2branches
    {
        if (s[j] == 'W')
            cntw++;
        else
            cntl++;
        if ((cntw >= 11 || cntl >= 11) && (cntw - cntl >= 2 || cntl - cntw >= 2))
        {
            cout << cntw << ':' << cntl << endl;
            cntw = 0, cntl = 0;
        }
    }
    if (cntw || cntl || (i-1)%11 == 0)
        cout << cntw << ':' << cntl << endl
             << endl;
    cntw = 0, cntl = 0;
    for (int j = 1; j < i; j++)//O(n) 2 branches
    {
        if (s[j] == 'W')
            cntw++;
        else
            cntl++;
        if ((cntw >= 21 || cntl >= 21) && (cntw - cntl >= 2 || cntl - cntw >= 2))
        {
            cout << cntw << ':' << cntl << endl;
            cntw = 0, cntl = 0;
        }
    }
    if (cntw || cntl || (i-1)%21 == 0)
        cout << cntw << ':' << cntl << endl;
}

P2670

问题一:越俎代庖的人工计算

起初想到的方法是对边界值进行特判,先判定四个角,然后对边上各位进行判定。
从而可以省下4n*x的判定次数。同时我们可以保证计算过程不用判定越界的问题;
使得复杂度降低。

这个冲突体现了人和计算机不可能同时轻松的矛盾。如果人为判定了定义域,那么计算机的效率将得到极大的提升;如果人把每次判定都交给计算机,计算机就会多花约一倍的时间。毕竟为了判定越界,每一个数对都要进行四次大小比较。这时很浪费时间的。
但这个问题当中,10000这个量级,实际上,常数并不很重要……这个时限并不会卡常数。

我们可以说,人越俎代庖考虑的东西越多,程序的稳健性和应对特例的能力可能会变差。毕竟像我这样的笨孩子,只能考虑到眼前这一点点东西……
同时如果人来考虑很多分支,手打大量代码,其实某种程度上说是对计算机做重复工作能力的不信任。这是荒谬的。

问题二:数学和实现

我们时常在进行编程设计的时候,会将二维数组的起始点定在左上角,这将对原有的数学知识形成不兼容,思考的时候容易错。
可行的方法是,要么完全建构一个类似于原有数学知识的环境。要么就把名称脱离数学。比如这里第二次我们将dx换成dr(即row的变化量)。

#include <bits/stdc++.h>
using namespace std;

char s[101][101];
int n, m, ans = 0, dr[8] = {-1, 0, 1, 1, 1, 0, -1, -1}, dc[8] = {-1, -1, -1, 0, 1, 1, 1, 0};

bool legal(int i, int j)
{
   if (i < 0 || i > n)
      return false;
   if (j < 0 || j > m)
      return false;
   return true;
}

int main()
{
#ifdef _LOC_
   freopen("1.in", "r", stdin);
   freopen("1.out", "w", stdout);
#endif
   cin >> n >> m;
   for (int i = 0; i < n; i++)
      for (int j = 0; j < m; j++)
         cin >> s[i][j];
   for (int i = 0; i < n; i++)
   {
      for (int j = 0; j < m; j++)
      {
         if (s[i][j] == '*')
         { 
            cout << '*';
            continue;
         }
         for (int k = 0; k < 8; k++)
            if (legal(i+dr[k], j+dc[k]))
               if (s[i+dr[k]][j+dc[k]] == '*')
                  ans++;
         cout << ans;
         ans = 0;
      }
      cout << endl;
   }
#ifdef _LOC_
   fclose(stdin);
   fclose(stdout);
#endif
   return 0;
}

//前车之鉴90分,过不了单线的情况 优化后确实能够体现良好的时间复杂度
#include <bits/stdc++.h>
using namespace std;
int main()
{
#ifdef _LOC_
   freopen("1.in", "r", stdin);
   freopen("1.out", "w", stdout);
#endif
   char area[101][101];
   int ans[101][101] = {};
   int dx[8] = {-1, -1, -1, 0, 1, 1, 1, 0}, dy[8] = {-1, 0, 1, 1, 1, 0, -1, -1};
   int a, b;
   cin >> a >> b;
   for (int i = 0; i < a; i++)
      for (int j = 0; j < b; j++)
         cin >> area[i][j];
   if (a == 1 && b == 1);
   else if (a == 1)
   {
      if (area[0][1] == '*')
         ans[0][0]++;
      for (int i = 1; i < b-1; i++)
      {
         if (area[0][i-1] == '*')
            ans[0][i]++;
         if (area[0][i+1] == '*')
            ans[0][i]++;
      }
      if (area[0][b-2] == '*')
         ans[0][b-1]++;
   }
   else if (b == 1)
   {
      if (area[1][0] == '*')
         ans[0][0]++;
      if (area[a-2][0] == '*')
         ans[a-1][0];
      for (int i = 1; i < a-1; i++)
      {
         if (area[i+1][0] == '*')
            ans[i][0]++;
         if (area[i-1][0] == '*')
            ans[i][0]++;
      }
   }
   else if (a >= 1 && b >= 1)
   {
      if (area[0][1] == '*')
         ans[0][0]++;
      if (area[1][0] == '*')
         ans[0][0]++;
      if (area[1][1] == '*')
         ans[0][0]++;

      if (area[a - 2][0] == '*')
         ans[a - 1][0]++;
      if (area[a - 1][1] == '*')
         ans[a - 1][0]++;
      if (area[a - 2][1] == '*')
         ans[a - 1][0]++;

      if (area[0][b - 2] == '*')
         ans[0][b - 1]++;
      if (area[1][b - 1] == '*')
         ans[0][b - 1]++;
      if (area[1][b - 2] == '*')
         ans[0][b - 1]++;

      if (area[a - 2][b - 1] == '*')
         ans[a - 1][b - 1]++;
      if (area[a - 1][b - 2] == '*')
         ans[a - 1][b - 1]++;
      if (area[a - 2][b - 2] == '*')
         ans[a - 1][b - 1]++;

      for (int i = 1; i < a - 1; i++)
      {
         for (int k = 3; k < 8; k++)
            if (area[i + dy[k]][dx[k]] == '*')
               ans[i][0]++;
         for (int k = 0; k < 5; k++)
            if (area[i + dy[(7 + k) % 8]][b - 1 + dx[(7 + k) % 8]] == '*')
               ans[i][b - 1]++;
      }
      for (int i = 1; i < b - 1; i++)
      {
         for (int k = 1; k < 6; k++)
            if (area[dy[k]][i + dx[k]] == '*')
               ans[0][i]++;
         for (int k = 0; k < 5; k++)
            if (area[a - 1 + dy[(5 + k) % 8]][i + dx[(5 + k) % 8]] == '*')
               ans[a - 1][i]++;
      }

      for (int i = 1; i < a - 1; i++)
         for (int j = 1; j < b - 1; j++)
            for (int k = 0; k < 8; k++)
            {
               if (area[i + dx[k]][j + dy[k]] == '*')
                  ans[i][j]++;
            }
   }
   for (int i = 0; i < a; i++)
   {
      for (int j = 0; j < b; j++)
         if (area[i][j] != '*')
            cout << ans[i][j];
         else
            cout << '*';
      cout << endl;
   }
#ifdef _LOC_
   fclose(stdin);
   fclose(stdout);
#endif
   return 0;
}

关于越俎代庖的第二个方法的说明:

  • 确实简省大量时间。如图
    在这里插入图片描述
    在这里插入图片描述
  • 但空间上由于四条边都是连续判定,所以有两条必然是竖着判的,不能进行边判断边输出。从而必须存下来再输出。这又体现了时间与空间复杂度的矛盾性。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值