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;
}
关于越俎代庖的第二个方法的说明:
- 确实简省大量时间。如图
- 但空间上由于四条边都是连续判定,所以有两条必然是竖着判的,不能进行边判断边输出。从而必须存下来再输出。这又体现了时间与空间复杂度的矛盾性。