7.14 天梯赛训练1

总结

  1. 直接懵逼的题目:
    1. (题9)连续因子——其实是因为理解错题目
    2. (题12)搜索树判断,还没怎么学,时间有限也还没补题。
  2. 看了没敢做的题目:
    1. (题6)城市间紧急救援:当时没能从签到题的状态切换过来,读完题目直接胆怯了,其实就是最短路的问题,但还是有些棘手的。
    2. (题11)链表去重:基础知识不完善吧,链表学的不太好,所以看到题目就直接放弃了,看过题解发现还是比较简单的,要巩固基础的知识体系。
    3. (题14)凑零钱:我知道是搜索问题啊,但是我不会做啊!菜到昏厥。
  3. 做了但没做全对的题目:
    1. (题13)肿瘤诊断(满分30拿25):第一反应就是用DFS做,然后不够熟练,中间有很多的问题,debug了很久,终于弄完了发现后两个测试点会爆栈;时间不够了就没用BFS去做。
    2. (题15)社交集群(满分30拿29):一个刁钻的并查集问题,对人进行处理的话,有一个神奇的测试点不让过,一定要对兴趣进行处理。
  4. 做了并通过的题目:
    1. (题1)打印沙漏
    2. (题2)Hello World
    3. (题3)计算摄氏温度
    4. (题4)求整数段和
    5. (题5)念数字
    6. (题7)个位数统计
    7. (题8)考试座位号
    8. (题10)月饼
      靠!这么一看,我做全对的只要签到题。继续加油吧!

1. 打印沙漏

传送门
就是一道简单的找图形规律,然后输出。好在天梯赛的训练没有罚时,不然我对这类题目的解决还是比较慢的。(加减困难)

#include<iostream>
#include<algorithm>
using namespace std;

int n, cnt;
char str;
void get(){
    for (int i = 1;; i+=2){
        if(i==1 && i<=n){    cnt++;n--;}    
        else if(2*i<=n){    cnt++;n -= 2 * i;}
        else    break;
    }
}

int main(){
    scanf("%d %c", &n, &str);
    get();
    for (int i = 0; i < cnt; i++){
        for (int j = 0; j < i; j++)    printf(" ");
        for (int j = 0; j < 2 * (cnt-i) - 1; j++)    printf("%c", str);
        printf("\n");
    }
    for (int i = cnt - 1; i > 0; i--){
        for (int j = 1; j < i; j++)    printf(" ");
        for (int j = 0; j < 2 * (cnt-i) + 1; j++)    printf("%c", str);
        printf("\n");
    }
    printf("%d\n", n);
    return 0;
}

2. hello world

3. 计算摄氏温度

4. 求整数段和

5. 念数字

好吧以上都是纯签到题,不附链接和代码了。

6. 紧急救援

传送门
是一道最短路的题目,修改一下Dijkstra的模板就能写。因为连续做了五道签到题,当时看到这个题目的时候,下意识是不敢去做的,然后做了后面的题目也没时间返回来解决这题了。后来补题发现,属实够呛。
跟普通的最短路问题相比,它多了一个人数的问题,即存在多条路径距离相等时,取路过城市救援人数和最多的路径(输入保证救援可行且最优解唯一。)又是第一次碰到这样的限制条件,做了很久,debug也很久,一度对着屏幕发呆怀疑人生)。然后我又意识到,我整理了这么久的最短路问题,最后写的时候,居然忘了怎么输出路径,[菜到哭泣.JPG]。
我补提时的问题都注释在代码中了,菜到昏厥,该长点记性了。

#include<iostream>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int inf = 0x3f3f3f3f;
const int num = 505;

struct edge{
    int u, v, w, mem;
    edge(int a, int b, int c, int d) { u = a;v = b;w = c;mem= d;}
};
vector<edge> e[num];

struct node{
    int id, mem, dist;
    node(int a, int b, int c) { id = a;dist = b;mem = c;}
    bool operator <(const node &x)const{   
        if(dist==x.dist)    return mem < x.mem;
        return dist > x.dist;
    }
};
//edge 和 node 中都多加了一个数据mem,用来存放该一个城市的救援人数,方便后续的比较
//node中的比较函数也有变化,在存在多条距离相同的路径时,选择救援人数和最多的路径

int n, m, s, d, ans=1;
int mem[num];
int dis[num];
int pre[num];
int nex[num];
//pre和nex,拿来输出路径,我当时真的忘记我自己整理的路径输出print_path了,菜到语塞。
int path[num];
//path统计最短路径的条数,这是这道题我爬的最久的坑
int done[num];
void dijkstra(){
    for(int i=0; i<=n; i++){
		dis[i] = inf;
		done[i] = path[i] = 0;
	}
	dis[s] = 0;
    path[s] = 1;
    priority_queue<node> q;
	q.push(node(s, dis[s], mem[s]));
    while(!q.empty()){
		node u = q.top();
		q.pop();
		if(done[u.id])	continue;
		done[u.id] = 1;//最短距离的确定标记依然适用,当时脑昏还把他给扔了
		for(int i=0; i<e[u.id].size(); i++){
			edge y = e[u.id][i];
			if(done[y.v])	continue;
			if(dis[y.v] > u.dist+y.w){
				dis[y.v] = u.dist + y.w;
                mem[y.v] = u.mem + y.mem;
                pre[y.v] = u.id;
                path[y.v] = path[u.id];
                q.push(node(y.v, dis[y.v], mem[y.v]));
			}
            else if(dis[y.v]==u.dist+y.w){
/* !最重要!*/  path[y.v] += path[u.id];//发现具有相同距离的两条路径之后,最短路数不能简单++!!!
                if(mem[y.v] < u.mem+y.mem){
                    mem[y.v] = u.mem + y.mem;
                    pre[y.v] = u.id;
                    q.push(node(y.v, dis[y.v], mem[y.v]));
                }
            }
		}
	}
}
int main(){
    scanf("%d%d%d%d", &n, &m, &s, &d);
    for (int i = 0; i < n; i++)    scanf("%d", mem + i);
    while(m--){
        int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		e[u].push_back(edge(u, v, w, mem[v]));
		e[v].push_back(edge(v, u, w, mem[u]));
    }
    dijkstra();
    int tem = d;
    while(tem!=s){
        nex[pre[tem]] = tem;
        tem = pre[tem];
    }
    // for (int i = 0; i < n; i++) printf("%d %d\n", i, path[i]);
    printf("%d %d\n", path[d], mem[d]);
    while(s!=d){
        printf("%d ", s);
        s = nex[s];
    }
    printf("%d\n", d);
    return 0;
}

7. 个位数统计

水题乱入,大概是队长拉题时拿来安慰我们的吧。

8. 考试座位号

传送门
一道简单的结构体排序,唯一要掌握的就是下面这个函数了。

friend bool operator<(const student &x, const student &y)
#include<iostream>
#include<algorithm>
using namespace std;

int n, m, a[1005];
struct student{
    char num[18];
    int a, b;
    friend bool operator<(const student &x, const student &y){
        return x.a < y.a;}
} stu[1005];

int main(){
    scanf("%d", &n);
    getchar();
    for(int i=1; i<=n; i++){
        scanf("%s%d%d", stu[i].num, &stu[i].a, &stu[i].b);
        getchar();
    }   
    scanf("%d", &m);
    for (int i = 0; i < m; i++)    scanf("%d", a + i);

    // for (int i = 1; i <= n; i++)    printf("%s %d %d\n", stu[i].num, stu[i].a, stu[i].b);  
    sort(stu + 1, stu + n + 1);
    // for (int i = 1; i <= n; i++)    printf("%s %d %d\n", stu[i].num, stu[i].a, stu[i].b);   
    for (int i = 0; i < m; i++)    printf("%s %d\n",stu[a[i]].num, stu[a[i]].b);
    return 0;
}

9. 连续因子

传送门
[强颜欢笑.JPG]当属理解错题目了,然后没思路,就一直没做,直到看了题解,直到读懂题目。[笑.JPG],我****,菜的好真实。

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

int start, len, cj = 1;
long long n;
int main(){
    scanf("%lld", &n);
    for(int i=2; i<=sqrt(n); i++){ 
		cj = 1;
		for(int j=i; cj*j<=n; j++){
			cj = cj*j;
			if(n%cj==0 && j-i+1>len){
				start = i;
				len = j-i+1;
			}
		}
	}
	if(start == 0){
		len=1;
		start=n;
	}
	cout<<len<<'\n'<<start;
	for(int i=start+1;i<start+len;i++){
		cout<<'*'<<i; 
	} 
	return 0;
}

10. 月饼

也算是水题吧,太常规的题目了,懒得附链接和代码了[狂妄.JPG]。

11. 链表去重

传送门
看题解之前:啊,链表,没怎么学,不会写。试探性地看了看题目,嗯,确实不会写。
看题解之后:呃,就这。其实还是能写的,主要还是没好好学链表,对这个比较陌生。

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
const int num = 100005;

int front, n;
int nex[num];
int vis[num];
int a[num];
int b[num];
struct node{    int key, next;} l[num];

int main(){
    scanf("%d%d", &front, &n);
    for (int i = 0; i < n; i++){
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        l[a].key = b, l[a].next = c;    
    }

    int cnt = 0;
    while(front!=-1){
        nex[cnt++] = front;
        front = l[front].next;
    }

    int c1 = 0, c2 = 0;
    for (int i = 0; i < cnt; i++){
        int k = l[nex[i]].key;
        if(vis[abs(k)]){
            b[c2++] = nex[i];
        }    
        else{
            a[c1++] = nex[i];
            vis[abs(k)] = 1;
        }
    }

    for (int i = 0; i < c1; i++){
        printf("%05d %d ", a[i], l[a[i]].key);
        if(i==c1-1)    printf("-1\n");
        else    printf("%05d\n", a[i+1]);
    }
    for (int i = 0; i < c2; i++){
        printf("%05d %d ", b[i], l[b[i]].key);
        if(i==c2-1)    printf("-1\n");
        else    printf("%05d\n", b[i+1]);
    }
    return 0;
}

12. 搜索树判断

传送门
超级重要,搁置了两天才补起来,查看了很多博客,发现这个是最简短的,花了些时间去理解,真的很好。

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const int manx = 1020;
const int INF = 0x3f3f3f3f;

bool isMirror;
int pre[1010];
vector<int> now;
void f(int l, int r) {
	if (l > r) return;
	int tr = l + 1;
	int tl = r;
	if (!isMirror) {
		while (tr <= r && pre[tr] < pre[l]) tr++;
		while (tl > l && pre[tl] >= pre[l]) tl--;
	}
	else {
		while (tr <= r && pre[tr] >= pre[l]) tr++;
		while (tl > l && pre[tl] < pre[l]) tl--;
	}
	if (tr - tl != 1) return;
	f(l + 1, tl);
	f(tr, r);
	now.push_back(pre[l]);
}

int main() {
	int n;
	scanf("%d", &n);
	for (int i = 0; i < n; ++i)
		scanf("%d", &pre[i]);
	f(0, n - 1);
	if (now.size() != n) {
		isMirror = 1;
		now.clear();
		f(0, n - 1);
	}
	if (now.size() != n) printf("NO");
	else {
		printf("YES\n%d", now[0]);
		for (int i = 1; i < n; ++i)
			printf(" %d", now[i]);
	}
	return 0;
}

13. 肿瘤诊断

传送门
刚学了搜索,来写这个还是够呛,看了练习还不够。用DFS后两个测试点会爆栈,一定要用BFS解决。无非变成了一个三维的空间问题,稍稍修改模板就能用。
然后是一个我和来问我问题的同学都一起犯的问题,存图的数组,开错大小,切记切记!

DFS爆栈代码

#include<iostream>
#include<algorithm>
using namespace std;

int m, n, l, t, s, sum;
int mp[61][1287][129];
int vis[61][1287][129];
int dir[][3] = {{1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}};

int jud(int i, int j, int k){
    if(i<1 || i>l || j<1 || j>m || k<1 || k>n)
        return 0;
    if(vis[i][j][k] || !mp[i][j][k])
        return 0;
    return 1;
}

void dfs(int i, int j, int k){
    if(s==t)        sum += t;
    else if(s>t)    sum++;
    // sum++;
    for (int a = 0; a < 6; a++){
        int ni = i + dir[a][0];
        int nj = j + dir[a][1];
        int nk = k + dir[a][2];
        if(jud(ni, nj, nk)){
            s++;
            vis[ni][nj][nk] = 1;
            dfs(ni, nj, nk);
        }    
    }
}

int main(){
    scanf("%d%d%d%d", &m, &n, &l, &t);
    for (int i = 1; i <= l; i++)
        for (int j = 1; j <= m; j++)
            for (int k = 1; k <= n; k++)
                scanf("%d", mp[i][j] + k);

    for (int i = 1; i <= l; i++)
        for (int j = 1; j <= m; j++)
            for (int k = 1; k <= n; k++)
                if(!vis[i][j][k] && mp[i][j][k]){
                    s = 1;
                    vis[i][j][k] = 1;
                    dfs(i, j, k);
                }
                    

    printf("%d\n", sum);
    return 0;
}

BFS通过代码

#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;

int sum;
int m, n, l, t;
int mp[70][1300][130];
int vis[70][1300][130];
int dir[][3] = {{1, 0, 0}, {-1, 0, 0}, {0, 1, 0}, {0, -1, 0}, {0, 0, 1}, {0, 0, -1}};
struct node{        int x, y, z;};

int jud(int i, int j, int k){
    if(i<1 || i>l || j<1 || j>m || k<1 || k>n)
        return 0;
    if(vis[i][j][k] || !mp[i][j][k])
        return 0;
    return 1;
}

void BFS(int i, int j, int k){
    int s = 1;
    queue<node> q;
    node front, next;
    front.x = i, front.y = j, front.z = k;
    q.push(front);

    while(!q.empty()){
        front = q.front();
        q.pop();

        for (int a = 0; a < 6; a++){
            next.x = front.x + dir[a][0];
            next.y = front.y + dir[a][1];
            next.z = front.z + dir[a][2];
            if(jud(next.x, next.y, next.z)){
                s++;
                vis[next.x][next.y][next.z] = 1;
                q.push(next);
            }    
        }
    }

    if(s >= t)
        sum += s;
}

int main(){
    scanf("%d%d%d%d", &m, &n, &l, &t);
    for (int i = 1; i <= l; i++)
        for (int j = 1; j <= m; j++)
            for (int k = 1; k <= n; k++)
                scanf("%d", mp[i][j] + k);

    for (int i = 1; i <= l; i++)
        for (int j = 1; j <= m; j++)
            for (int k = 1; k <= n; k++)
                if(jud(i, j, k)){
                    vis[i][j][k] = 1;
                    BFS(i, j, k);
                }

    printf("%d\n", sum);
    return 0;
}

14. 凑零钱

传送门
又是一道搜索问题,就是不知道怎么处理。注意剪枝!

#include<iostream>
#include<algorithm>
using namespace std;
const int num = 1005;

int n, m, flag;
int a[num];
int b[num];
int c[num];

void dfs(int i, int cnt, int sum){
    if(flag || sum+b[i]<m)    return;
    if(i==n || sum>=m){
        if(sum==m){
            flag = 1;
            printf("%d", c[0]);
            for (int i = 1; i < cnt; i++)    printf(" %d", c[i]);
            printf("\n");
        }
        return;
    }
    c[cnt] = a[i];
    dfs(i + 1, cnt + 1, sum + a[i]); 
    dfs(i + 1, cnt, sum);
}

int main(){
    scanf("%d %d", &n, &m);
    for (int i = 0; i < n; i++)
    scanf("%d", a + i);

    sort(a, a + n);
    b[n - 1] = a[n - 1];
    for (int i = n - 1; i >= 0; i--)    b[i] = b[i + 1] + a[i];
    dfs(0, 0, 0);

    if(!flag)    printf("No Solution\n");
    return 0;
}

15. 社交集群

传送门
并查集的问题,只是一个人可以有很多很多的爱好,然后要让有相同爱好的人联系起来。我最开始写的代码是对人进行处理的,调整了很多很久,最后还是有一个测试点不过,满分30拿了29,不知道卡在哪个神奇的地方。然后第二种是对兴趣进行处理。

扣了1分的代码

#include<iostream>
#include<algorithm>
using namespace std;
const int num = 1005;

int n, sum;
int hob[num][num], h[num];
int s[num],m[num];

bool cmp(int &a, int &b) { return a > b; }
void init(){
	for(int i=0; i<num; ++i)	s[i] = i;
}

int find(int x){
    return s[x] == x ? x : s[x] = find(s[x]);
}

void sunion(int x, int y){
	x = find(x);
	y = find(y);
	s[y] = x;
}

int main(){
    init();
    scanf("%d", &n);
    for (int i = 1; i <= n; i++){
        int a;
        scanf("%d:", &a);
        while(a--){
            int x;
            scanf("%d", &x);
            hob[x][h[x]++] = i;//i有兴趣x
            if(h[x]>1)    sunion(i, hob[x][h[x]-2]);
        }
    }

    for (int i = 1; i <= n; i++){
        if(s[i]==i)    sum++;
        m[find(i)]++;
    }
        
    printf("%d\n", sum);
    sort(m, m + n, cmp);
    for (int i = 0; i < sum; i++){
        if(i==sum-1)    printf("%d\n", m[i]);
        else    printf("%d ", m[i]);
    }
    return 0;
}

对兴趣处理的满分代码

#include<iostream>
#include<algorithm>
using namespace std;
const int num = 1005;

int n, sum;
int height[num];
int s[num], mem[num];

bool cmp(int &a, int &b) { return a > b;}
void init(){
	for(int i=0; i<num; ++i){
		s[i] = i;
		height[i] = 0;
	}
}

int find(int x){
	int r = x;
	while(s[r] != r)	r = s[r];
	int i=x, j;
	while(i != r){
		j = s[i];
		s[i] = r;
		i = j;
	}
	return r;
}

void sunion(int x, int y){
	x = find(x);
	y = find(y);
	if(height[x] > height[y])
		s[y] = x;
	else{
		s[x] = y;
		if(height[x] == height[y])
			height[y]++;
	}
}

int main(){
    init();
    scanf("%d", &n);
    for (int i = 1; i <= n; i++){
        int a, t;
        scanf("%d:%d", &a, &t);
        a--;
        while(a--){
            int x;
            scanf("%d", &x);
            sunion(t, x);
        }
        mem[find(t)]++;
    }

    for (int i = 1; i < num; i++){
        int fi = find(i);
        if(mem[i]){
            if(i==fi)    sum++;
            else{
                mem[fi] += mem[i];
                mem[i] = 0;
            }
        }    
    }
    sort(mem, mem + num, cmp);
    printf("%d\n", sum);
    for (int i = 0; i < sum; i++){
        if(i==sum-1)    printf("%d\n", mem[i]);
        else    printf("%d ", mem[i]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值