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

排座位

作者 陈越 单位 浙江大学 代码长度限制 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");
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值