2020-10-03 PTA 天梯赛练习题题解

    科技2022-07-14  135

    文章目录

    排座位题意题解代码 7-12 分而治之题意题解代码

    排座位

    作者 陈越 单位 浙江大学 代码长度限制 16KB 时间限制 200 ms 内存限制 64 MB

    题意

    输入n,k,m,n表示一共有n个人要进行排座位,m条关系条数(A B S i S_i Si)表示A和B之间的关系为 S i S_i Si,然后进行k次查询,问两人是否能连着坐在一起

    关系为1表示是朋友,-1表示是死对头

    对每个查询输出一行结果:

    如果两位宾客之间是朋友,且没有敌对关系,则输出No problem;如果他们之间并不是朋友,但也不敌对,则输出OK;如果他们之间有敌对,然而也有共同的朋友,则输出OK but…;如果他们之间只有敌对关系,则输出No way。

    题解

    通过二维数组存储两人之间的关系,由于两人之间的关系是唯一的,所以可以看做是 双向边

    纯枚举做法不管怎么改都过不去,而最好的情况也会有全联通的测试点无法通过,因此判断是后能满足条件

    因此,上网查询了一下并查集做法

    未得分点:最大N,全连通环,全查询

    acwing并查集 模板题

    find(x) 是找会祖宗节点, p[x] 数组存放的是父节点

    代码

    #include <iostream> #include <cstring> #include <cstdio> using namespace std; const int MAXN = 111; int p[MAXN]; int find(int x) { if (p[x] == x) return p[x]; return p[x] = find(p[x]); } //把能够成为好友的全部合并到一个根上 void merge(int x, int y){ int t1 = find(x); int t2 = find(y); if (t1 != t2){ p[t1] = t2; } } int gx[MAXN][MAXN]; int main(){ int n, m, k; scanf("%d%d%d", &n, &m, &k); for(int i = 1; i <= n; i++) p[i] = i; for(int fi = 1; fi <= m; ++fi) { int a, b, c; scanf("%d%d%d", &a, &b, &c); gx[a][b] = c; gx[b][a] = c; if (c == 1) merge(a, b); } for(int qu = 1; qu <= k; ++qu){ int qa, qb; scanf("%d%d", &qa, &qb); if (gx[qa][qb] == 1) puts("No problem"); else if (gx[qa][qb] == -1){ if (find(qa) == find(qb))puts("OK but..."); else puts("No way");} else {if (find(qa) == find(qb)) puts("No problem"); else puts("OK");} } }

    7-12 分而治之

    题意

    我们希望首先攻下敌方的部分城市,使其剩余的城市变成孤立无援,然后再分头各个击破。为此参谋部提供了若干打击方案。本题就请你编写程序,判断每个方案的可行性。

    题解

    建图,数据大小和多边的存在,因此更适合vector的动态二维数组去建立邻接表,像最短路那样建

    处理,通过vis去进行标记,vis[x] = 1说明这个城市已经被攻下了

    访问,通过两层for循环去进行遍历,外层城市总数,内层该城市所连接的v[i].size()座城市

    v i s [ i ] = = 0 且 v i s [ v [ i ] [ j ] ] = = 0 vis[i] == 0 且 vis[v[i][j]] == 0 vis[i]==0vis[v[i][j]]==0的时候就说明存在城市不是孤立无援的,因此直接标记为策略失败

    代码

    #include <iostream> #include <cstring> #include <vector> #include <algorithm> using namespace std; const int maxn = 1e5 + 1111; const int N = 111; int vis[maxn]; vector<int> v[maxn]; // 链接表 void init1(){ memset(vis, 0, sizeof vis); } int main(){ int n, m; cin >> n >> m; for(int si = 1; si <= m; si++){ int a, b; cin >> a >> b; //双向边 v[a].push_back(b); v[b].push_back(a); } int k; cin >> k; // k种方案,使其剩余的城市变成孤立无援 for(int sk = 1; sk <= k; ++sk){ bool flag = true; //用于判断是否能够攻击成功 init1(); int np; cin >> np; for(int sp = 1; sp <= np; ++sp){ int x; cin >> x; vis[x] = 1; //x城市已经被进攻 } for(int i = 0; i < n; i++){ for(int j = 0; j < v[i].size(); j++){ if (vis[i] == 0 && vis[v[i][j]] == 0){ //确保都没进攻过 flag = false; } } } (flag) ? puts("YES") : puts("NO"); } }
    Processed: 0.013, SQL: 8