Atcoder 361个人补题(D,E,F)

D.Go Stone Puzzle

原题链接D - Go Stone Puzzle (atcoder.jp)

题目大意

思路

首先将能直接判断的情况单独处理,然后使用BFS处理剩下的情况。

直接判断的情况:

1.只有一块砖或者两块砖,这种情况下题目操作并不能改变什么,比较s与t即可;

2.如果s与t的同色砖数量不同,那么肯定不可能将s操作成t;

3.s==t,答案为0; 

剩余情况通过BFS找出来,队列里存储二元组{当前字符串,操作次数},使用unordered——map标记字符串是否已经加入队列,暴力找出所有情况即可。

代码如下:

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

int n;
string s,t;
queue<pair<string,int>> q;  //{当前字符情况,当前操作次数}
unordered_map<string,int> v;    //用于标记当前字符串情况是不是已经出现过

void bfs()
{
    s+="  ";
    t+="  ";    //均补充两个空位
    v[s]=1;     //标记初始字符串情况为1
    q.push({s,0});  //队列添加初始情况
    while(q.size())
    {
        auto [ns,num]=q.front();    //取出当前字符串和操作次数
        q.pop();
        int pos;

        for(int i=0;i<ns.size();i++)
        {
            if(ns[i]==' ')
            {
                pos=i;  //找到第一个为空位
                break;
            }

        }

        for(int i=0;i<ns.size()-1;i++)
        {
            if(ns[i]!=' ' && ns[i+1]!=' ')  //满足可操作的情况
            {
                string news=ns;     //将当前字符串用另一个字符串存下
                swap(news[i],news[pos]);
                swap(news[i+1],news[pos+1]);    //进行换位操作

                if(news==t)     //换位后成为t直接输出,程序结束
                {
                    cout<<num+1<<endl;
                    return ;
                }

                if(v[news])     //如果已经标记过则跳过,否则标记,加入队列;
                    continue;
                v[news]=1;
                q.push({news,num+1});
            }
        }
    }
    cout<<-1<<endl;     //搜完所有情况无法变成t,输出-1;

}

void slove()
{
    cin>>n>>s>>t;

    if(s.size()==1 || s.size()==2)
        if(s!=t)    //如果只有一块砖或者两块砖无法变换形式,s!=t直接输出-1;
        {
            cout<<-1<<endl;
            return ;
        }
    int ans1=0,ans2=0;  //记录白砖数量
    for(int i=0;i<s.size();i++)
    {
        if(s[i]=='w')
            ans1++;
        if(t[i]=='w')
            ans2++;
    }
    if(ans1!=ans2)  //同色砖数量不同必然不能操作成功
    {
        cout<<-1<<endl;
        return ;
    }
    if(s==t)    //不需要操作
    {
        cout<<0<<endl;
        return ;
    }
    bfs();  //广搜剩下的情况
}


signed main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int _=1;
    //cin>>_;
    while(_--)
    {
        slove();
    }
    return 0;
}

E - Tree and Hamilton Path 2

原题链接E - Tree and Hamilton Path 2 (atcoder.jp)

题意

 知识点:树的直径

思路: 要走完所有的城市,必然会有一些路要走两遍,最后结果就是(所有的路总长)*2-只走一边的长度。所以要使距离最短就是使起点到终点的无重复路径最长。所以这个题目将图想象成树,只要求出树的直径就好。可以通过两遍dfs或者dfs+dp来解决,我这里先只写两遍dfs的解法。

代码

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

int n,s,sum;    //n为城市数,s为找到的起点和终点,sum为两倍的所有边的权重
vector<pair<int,int>> e[200005];    //邻接矩阵存储边的信息{终点,权重}
int dep[200005];    //从起点到该点的最长距离

void dfs(int st,int ed)    
{
    if(dep[ed]>dep[s])    //当前距离长度大于起点长度,更新起点;
        s=ed;
    for(int i=0;i<e[ed].size();i++)    //遍历子节点;
    {
        int x=e[ed][i].first;    
        int y=e[ed][i].second;
        if(x!=st)
        {
            dep[x]=dep[ed]+y;    //更新子节点长度
            dfs(ed,x);   
        }

    }
}

void slove()
{
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int a,b,c;
        cin>>a>>b>>c;
        e[a].push_back({b,c});   
        e[b].push_back({a,c});    //无向图存两遍
        sum+=2*c;
    }
    dfs(0,1);    //第一遍用于找到最深的叶子节点作为起点;
    dep[s] = 0;
    dfs(0,s);    //第二遍用于找到离起点最远的叶子节点;
    cout << sum-dep[s] << endl;

}


signed main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int _=1;
    //cin>>_;
    while(_--)
    {
        slove();
    }
    return 0;
}

F . x = a^b

原题链接F - x = a^b (atcoder.jp)

题目大意

 思路:刚开始就写的暴力,然后直接超时,因为要枚举到,复杂度太大会超时,然后将指数b分为两个部分, b=2和b>=3。当b=2时,那么x的数量就为,即为所有的完全平方数。再考虑b=3的部分,直接枚举到,然后用map去将每一个x进行标记,避免重复计数。再通过判断该数是否为完全平方数,如果是,也计数下来,因为如果他是完全平方数则属于b=2的一部分,后续计算避免进行去重。最后计算即(b=2的x数量)  +  (b>=3的x数量)- (b>=3时记录的完全平方数的数量)。

代码

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

map<int , bool> mp;

void slove()
{
    int n,ans=0,num=0;
    cin>>n;
    for(int i=2;i*i*i<=n;i++)    //从2开始枚举,先忽略a=1的情况
    {
        int x=i*i;
        while(x<=n/i)
        {
            x*=i;
            if(mp[x])    //已标记过
                continue;
            if((int)sqrtl(x)*sqrtl(x)==x)
                num++;    //b>=3时的完全平方数
            mp[x]=1;    //标记
            ans++;    //b>=3所有的x数量
        }
    }
    cout<<(int)sqrtl(n)+ans-num<<endl;    //b=2时的sqrtl(n)包含1

}


signed main()
{
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    int _=1;
    //cin>>_;
    while(_--)
    {
        slove();
    }
    return 0;
}

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值