2020团体程序设计天梯赛题解(部分)

文章目录

  • 个人题解:这里我只写我个人认为应该写的题解,太简单的就不写了
  • L2-2 口罩发放 (25分)
    • 思路:正解
  • L2-3 完全二叉树的层序遍历 (25分)
    • 思路:正解
  • L2-4 网红点打卡攻略 (25分)
    • 思路:正解
  • L3-1 那就别担心了 (30分)
    • 思路1:骗分
    • 思路2:正解

这次天梯赛拖后腿了,好几道应该作对的题目都没搞出来

个人题解:这里我只写我个人认为应该写的题解,太简单的就不写了

L2-2 口罩发放 (25分)

思路:正解

  • 这个题的难点不在于题目,而在于你的读题水平,记住这个题的几个约束条件。1、身份证号必须是18位。2、同一个人在第i天申请成功,则需要等到i + P + 1天才能再次申请。3、每天有S个名额,直到发完为止。4、排序首先按照提交的时间排序,如果时间相同的话,那么按照次序,也就是当天提交时候的顺序。5、答案1记录每天发放的口罩的人的姓名和身份号,答案2记录所有的身体状况位1的人,按照顺序记录,而且只记录一次。所以这个要在排序之前就记录下来每天的身体状况为1的人
#include 
using namespace std;
const int N = 1100;
struct edge{
    
    string name;
    string id;
    int heal;
    int times;
    int ci;
};
int D,P,S,T;
bool check(string id)
{
    if(id.size() != 18){
        return false;
    }
    
    for(int i = 0;i < 18;i ++)
    {
        if(id[i] < '0' || id[i] > '9'){
            return false;
        }
    }
    return true;
}

bool cmp(edge e1,edge e2)
{
    if(e1.times == e2.times){
        return e1.ci < e2.ci;
    }
    return e1.times < e2.times;
}
mapmp;
setst;
vector>res;
int main()
{
    cin >> D >> P;
    
    for(int i = 1;i <= D;i ++)
    {
        cin >> T >> S;
        vectorv;
        for(int j = 0;j < T;j ++)
        {
            edge e;
            int a,b;
            cin >> e.name >> e.id >> e.heal;
            scanf("%d:%d",&a,&b);
            e.times = a*60 + b;
            e.ci = j;
            if(check(e.id)){
                if(e.heal == 1){
                    if(!st.count(e.id)){
                        st.insert(e.id);
                        res.push_back({e.name,e.id});
                    }
                }
                v.push_back(e);
            }
        }
        sort(v.begin(),v.end(),cmp);
        
        vector>ans;
        for(auto &x : v)
        {
            string id = x.id;
            if(S == 0) break;
            if(mp[id] <= i){
                mp[id] = i + P + 1;
                ans.push_back({x.name,x.id});
                S --;
            }
        }
        
        for(auto &x : ans){
            cout << x.first << ' ' << x.second << endl;
        }
    }
    for(auto &x : res){
        cout << x.first << ' ' << x.second << endl;
    }
    
    return 0;
}

L2-3 完全二叉树的层序遍历 (25分)

思路:正解

  • 这个题开始没做出来,今天补题的时候发现这个很简单,应该是这个4道题目里最简单的一道题目了,淦;给你一个完美二叉树的后序遍历,然后写出其层序遍历,还是见图说话吧
    2020团体程序设计天梯赛题解(部分)_第1张图片
#include 
using namespace std;
const int N = 1000;

struct edge{
    int data;
    int left;
    int right;
}t[N];
vectorans;

void dfs(int u)
{
    if(u == 0){
        return;
    }
    dfs(t[u].left);
    dfs(t[u].right);
    ans.push_back(u);
}
int a[N];
int b[N];

int main()
{
    int n;
    cin >> n;
    for(int i = 1;i <= 30;i ++)
    {
        t[i].data = i;
        
        if(i * 2 > n){
            break;
        }
        t[i].left = i * 2;
        if(i * 2 + 1 > n){
            break;
        }
        t[i].right = i * 2 + 1;
    }
    
    dfs(1);
    
    for(int i = 1;i <= n;i ++)
    {
        cin >> a[i];
    }
    
    bool is_k = false;
    
    for(int i = 0;i < ans.size();i ++)
    {
        int t = ans[i];
        b[t] = a[i + 1];
    }
    
    for(int i = 1;i <= n;i ++)
    {
        if(is_k) cout << ' ';
        is_k = true;
        cout << b[i];
    }
    
    return 0;
}

L2-4 网红点打卡攻略 (25分)

思路:正解

  • 给你一个路径,判断这条路径是否是一个NP完全问题的解,如果是找出路径最短的那个解,而且还得记录有多少个正确的解
  • 这个题要判断给的点是否是n个不同的点就好了。1、p等于n。2、这p个点没有重复的点
#include  
using namespace std;

const int N = 210;

int g[N][N];
int n,m;
int k,p;

int road[N];
long long id,ans = 1e9;
long long sum;
bool check()
{
	sum = 0;
	sum += g[0][road[1]];
	
	for(int i = 1;i < p;i ++)
	{
		int x = road[i],y = road[i + 1];
		sum += g[x][y];	
	}
	sum += g[road[p]][0];
	
	if(sum >= 1e9){
		return false;
	}
	return true;
}
int main()
{
	cin >> n >> m;
	
	memset(g,0x3f,sizeof g);
	
	for(int i = 0;i < m;i ++)
	{
		int a,b,c;
		cin >> a >> b >> c;
		g[a][b] = g[b][a] = min(g[a][b],c);
	}
	
	cin >> k;
	int cnt = 0;
	
	for(int i = 1;i <= k;i ++)
	{
		cin >> p;
		setss; 
		for(int j = 1;j <= p;j ++)
		{
			cin >> road[j];
			ss.insert(road[j]);
		}
		
		if(p == n && ss.size() == n && check()){
			if(ans > sum){
				ans = sum;
				id = i;
			}
			cnt ++;
		}
	}
	
	cout << cnt << endl;
	cout << id << ' ' << ans << endl;
	
	return 0;
}

L3-1 那就别担心了 (30分)

思路1:骗分

  • 暴力搜索,据说bfs爆内存,我用的dfs,卡时间,只需要从起点搜索道终点,看看有多少条路就好了,这样,再搜索的过程中判断时候有一个点,不能到达任何一个点(也就是判断融洽关系)
#include 
using namespace std;
const int N = 1e6 + 10;

int h[N],e[N],ne[N],idx;

int n,m;
int S,E;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}

int ans;
bool st[N];
bool flag = true;
void dfs(int u)
{
    if(u == E){
        ans ++;
        return;
    }
    if(u != E)
    {
        if(h[u] == -1){
            flag = false;
        }
    }
    for(int i = h[u];~i;i = ne[i])
    {
        int j = e[i];
        dfs(j);
    }
}


int main()
{
    memset(h,-1,sizeof h);
    
    cin >> n >> m;
    for(int i = 0;i < m;i ++)
    {
        int a,b;
        cin >> a >> b;
        add(a,b);
    }
    cin >> S >> E;
    dfs(S);
    
    if(flag){
        cout << ans << ' ' << "Yes" << endl;
    }else{
        cout << ans << ' ' << "No" << endl;
    }
    
    return 0;
}

思路2:正解

  • 记忆化搜索
#include 
using namespace std;
const int N = 1e6 + 10;

int h[N],e[N],ne[N],idx;

int n,m;
int S,E;

void add(int a,int b)
{
    e[idx] = b,ne[idx] = h[a],h[a] = idx ++;
}

int ans[N];
bool st[N];
bool flag = true;
int dfs(int u)
{
    if(h[u] == -1 && u != E){
        flag = false;
    }
    st[u] = true;
    if(ans[u]) return ans[u];
    for(int i = h[u];~i;i = ne[i])
    {
        int j = e[i];
        ans[u] += dfs(j);
    }
    
    return ans[u];
}


int main()
{
    memset(h,-1,sizeof h);
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for(int i = 0;i < m;i ++)
    {
        int a,b;
        cin >> a >> b;
        add(a,b);
    }
    cin >> S >> E;
    ans[E] = 1;
    dfs(S);
    
    if(flag){
        cout << ans[S] << ' ' << "Yes" << endl;
    }else{
        cout << ans[S] << ' ' << "No" << endl;
    }
    
    return 0;
}

总结:主要问题还是自己本身菜,读题太慢了,打代码的速度也太慢了

你可能感兴趣的:(PTA天梯题目)