今天按照安排应该是进行一次有关搜索的测试,主要是针对昨天所学的内容
T1
这一道t1其实正解是用二分做的,二分结果即可。
出现的错误:
在比赛时首先没有看清题目,以为每一个瓶盖之间的距离相等,即都是等距的。这直接导致GG,而且在做题的过程中心态并不平和,出现错误查不出来就很烦躁,然后恶性循环下去,这并不是一个好的事情。之后要调整。
二分的正确性:
因为这个答案显然是单调的,单调是满足二分的一个比较明显的标准,我们可以先把这一组数据进行排序,使满足单调的特性。当我们二分一个中间值作为一个答案的话,如果从第一个开始往后向后找,开始计数。如果计数大于等于 m 的话。 那么答案会在[mid,right]之间,如果计数小于 m 的话,答案就在[left,mid)之间,然后重复二分的过程,答案就在l-1处了。
标程:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using namespace std;
int a[1000005];
int l, r;
int n,m;
int main()
{
scanf("%d %d", &n,&m);
for (int i=1;i<=n;++i)
scanf("%d", &a[i]);
sort(a+1,a+n+1);
l = 1; r = a[n] - a[1];
while (l <= r)
{
int now(1);
int times(1);
int mid=(l + r)/2;
for (int i = 2; i <= n; ++i)
if (a[i] - a[now] >= mid)
{
++times;
now = i;
}
if (times >= m)
{
l = mid + 1;
}
else
r = mid - 1;
}
printf("%d\n", l-1);
return 0;
}
需要注意二分的端点问题,开区间与闭区间的区别。
T2
正解的算法是BFS,而我却当成一道图论题去做了(虽然在图论里BFS也是一种算法)这道题写的显然就是没有思考的结果,直接打最暴力的方法,根本不去思考了。
关于BFS算法的正确性:
因为BFS遍历到的点都是第一次走到,所以只要每遍历到一次就把计数加一即可,当
该点在此次遍历的过程中被记录的话,我们需要考虑的就是次数的转移。
挺经典的一个算法,之后又gdb跟踪了一下,搞懂标程了,贴下代码,带注释:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
using namespace std;
int n,m;
int d[100010],sum[100010];
bool v[100010];
vector<int> a[10010];
const int mod=100003;
inline int Read()
{
int Num=0,F=1; char ch=getchar();
while (!isdigit(ch)) {if (ch == '-') F=-1; ch=getchar();}
while ( isdigit(ch)) {Num=(Num<<1)+(Num<<3)+ch-'0'; ch=getchar();}
return Num*F;
}
void init()// 用vector数组来存无向图
{
n=Read();m=Read();
int xx,yy;
for (int i=1;i<=m;++i)
{
xx=Read();yy=Read();
a[xx].push_back(yy);// 即在xx 与 yy之间存在一条边,即yy为xx的子节点
a[yy].push_back(xx);
}
}
void bfs()
{
queue<int> q; q.push(1);d[1]=0;sum[1]=1;v[1]=1;// 1为根节点所以深度为0,
while (!q.empty())
{
int x=q.front(); q.pop();
for (int i=0;i<a[x].size();++i)
{
int t = a[x][i];
if (!v[t])
{
v[t]=1;// 将该点标记,防止再次遍历。
d[t]=d[x]+1;// 维护BFS的层数,当探到新的点以后说明这一层已经结束,将当前点的层数加上1即为新的子节点的层数。
q.push(t);// 将本节点的子节点入队
}
if(d[t] == d[x] + 1)// 当当前点的子节点的层数比当前点的层数多一的话,将子节点的路径数更新,由上一层的根节点加上当前的子节点原来就有的路径数即可。
sum[t]=(sum[x]+sum[t]) % mod;
}
}
}
int main()
{
init();
bfs();
for (int i=1;i<=n;++i)
printf("%d\n", sum[i]);
return 0;
}
在这其中有一些很巧妙的东西,可以学习。
T3
这是一道很不容易拿满分的题吧,普通纯算法好像得不了全分。
正解是用重新构图然后跑一边SPFA得到的答案。
而我,又打出了最暴力的算法….,Dijastra加上dfs判断路径,复杂度直接爆掉。于是很惨的拿了10分。
正解思路:
重新构图,把每个点拆成 k + 1 个点,共连 2 * k 条边,如果消耗一次免费乘车的机会就把n与n相连的下一个点的边权设置成0,重构完图后,跑一遍最短路算法,得到的答案就是所求的答案了。
正解:
1 |
|
总结
整体来说还好,打题状态不错,神经紧绷起来了,但是这种题最怕不进行思考,只打暴力,只套板子,其实有一些题想一想结论也不是很难,注意写题要思考,而不是无目的的刷题。
感觉自己正在不断进步吧,不论是知识水平,还是心里状态。毕竟用贪心的角度想一下,在当前阶段,最优决策就是不断学习与进步,提高自己,别忘了!不要太在乎之前和之后的状态,因为只要保证当前决策是最优的,那么这个照这样进行下去,得到的一定是一个全局最优解!
//别忘了你来这里是干什么的!!
成绩会反应一些问题,但是只要保证自己在不断提高自己,这些暂时的东西都影响不大!调整好状态,继续出发!