个人赛 The 2017 North America Qualification Contest 部分题解

这篇博客探讨了图论中的最短路径问题,通过Dijkstra算法解决带有免费机票的旅行路线。同时,文章讨论了如何判断一个货币系统是否最优,使用完全背包和贪心策略进行比较。最后,介绍了如何通过模拟找到导致无法从起点到达终点的错误指令。涉及的主要算法包括Dijkstra、贪心算法和字符串操作。
摘要由CSDN通过智能技术生成

比赛链接

B - Bumped!
题意:
给定n个点m条边组成的无向图,给定起点和终点,其中会提供机票使有的线路直接到达无需花费(单程且只能选择一次),求从起点到终点的最短路。
题目分析:
首先明确机票可以选择也可以不选择,可以先跑一遍dijkstra找出最短距离,然后加入机票航线并不断更新最小值,且每次更新完需要删除新加入的机票航线,当时删除边的操作脑子有点乱,当时数组模拟邻接表有点遗忘h数组的含义
代码:

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
typedef set<int>::iterator SIT;
int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
int lcm(int a,int b) {return a/gcd(a,b)*b;}
const double eps=1e-6;
const int INF=0x3f3f3f3f,mod=1e9+7;
const int N=1e6+10;
int dis[N];
bool st[N];
int h[N],e[N],ne[N],idx,w[N];
int n,m,q,start,ed;
void add(int a,int b,int c)
{
    w[idx]=c;
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}
int dij(int start,int ed)
{
    memset(dis,0x3f,sizeof(h));
    memset(st,0,sizeof(st));
    dis[start]=0;
    priority_queue<PII,vector<PII>,greater<PII>>heap;
    heap.push({0,start});
    while(heap.size()){
        auto t=heap.top();
        heap.pop();
        int u=t.se;
        if(st[u]) continue;
        st[u]=true;
        for(int i=h[u];i!=-1;i=ne[i]){
            int j=e[i];
            if(dis[j]>dis[u]+w[i]){
                dis[j]=dis[u]+w[i];
                heap.push({dis[j],j});
            }
        }
    }
    return dis[ed];
}
signed main()
{
    fast;
    cin>>n>>m>>q>>start>>ed;
    memset(h,-1,sizeof(h));
    while(m--){
        int a,b,c;
        cin>>a>>b>>c;
        add(a,b,c);
        add(b,a,c);
    }
    int minv=dij(start,ed);
    while(q--){
        int a,b;
        cin>>a>>b;
        int x=h[a];
        add(a,b,0);
        minv=min(minv,dij(start,ed));
        h[a]=x;
    }
    cout<<minv<<endl;
    return 0;
}

C - Canonical Coin Systems
题意:
求给定的货币系统贪心凑钱是不是最优策略
题目分析:
n的范围很小,分别求出完全背包和贪心组成所有钱的方案数,然后逐个比较,输出答案即可。
代码:

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
typedef set<int>::iterator SIT;
int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
int lcm(int a,int b) {return a/gcd(a,b)*b;}
const double eps=1e-6;
const int INF=0x3f3f3f3f,mod=1e9+7;
const int N=2e6+10;
int w[N],n;
int dp[N];
int getmax[N];
signed main()
{
    fast;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>w[i];
    memset(dp,0x3f,sizeof(dp));
    dp[0]=0;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=N;j++)
            if(j>=w[i])
                dp[j]=min(dp[j],dp[j-w[i]]+1);

    for(int i=0;i<=N;i++)
        for(int j=1;j<=n;j++)
            if(i>=w[j])
               getmax[i]=getmax[i-w[j]]+1;

    bool flag=true;
    for(int i=0;i<N;i++)
        if(getmax[i]!=dp[i]){
            flag=false;
            break;
        }
    if(flag) cout<<"canonical"<<endl;
    else cout<<"non-canonical"<<endl;
    return 0;
}

F - GlitchBot
题意:
给定n条指令,其中一条发生错误无法从起点到达终点,起点坐标起始方向固定,求出错误指定。
题目分析:
暴力枚举所有指令,然后每次替换掉指令,根据指令模拟走一遍,如果可以到达终点输出答案,细节方面注意下方向的定义顺序,每次记得恢复现场。
果然暴力也是需要技巧的,自己写的思路很混乱。

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
typedef set<int>::iterator SIT;
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
int lcm(int a,int b) {return a/gcd(a,b)*b;}
const double eps=1e-6;
const int INF=0x3f3f3f3f,mod=1e9+7;
const int N=2e6+10;
string step[60];
int x,y,n;
string t[]={"Forward","Right","Left"};
bool judge(string step[])
{
    int sx=0,sy=0,turn=1;//方向定义顺序为右上左下,方向初始向上turn初始为1
    for(int i=0;i<n;i++){
        if(step[i]=="Forward"){
            sx+=dx[turn];
            sy+=dy[turn];
        }
        else if(step[i]=="Right"){
            turn--;
            if(turn<0) turn=3;
        }
        else if(step[i]=="Left"){
            turn++;
            if(turn>3) turn=0;
        }
    }
    if(sx==x&&sy==y) return true;
    else return false;
}
signed main()
{
    cin>>x>>y>>n;
    for(int i=0;i<n;i++) cin>>step[i];
    for(int i=0;i<n;i++){
        string p=step[i];
        for(int j=0;j<3;j++){
            step[i]=t[j];
            if(judge(step)){
                cout<<i+1<<' '<<step[i]<<endl;
                return 0;
            }
            step[i]=p;//复原
        }
    }
    return 0;
}

G - Greeting Card
题意:
求n个点中距离为2018坐标对的数量
题目分析:
其实给定的样例就能提醒我们打表看看规律,不难发现距离2018的点,满足:①x距离差2018,y相等 ②x相等,y差2018 ③x差1680,y差1118 ④x差1118,y差1680,我们存下来这12种情况,然后遍历每个点的12个方向,如果存在这个点,答案加一。
其中用map+pair记录出现次数。
代码:

#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define pf push_front
#define int long long
#define fast ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
typedef set<int>::iterator SIT;
int dx[]={0,-1,0,1},dy[]={-1,0,1,0};
int gcd(int a,int b) {return b?gcd(b,a%b):a;}
int lcm(int a,int b) {return a/gcd(a,b)*b;}
const double eps=1e-6;
const int INF=0x3f3f3f3f,mod=1e9+7;
const int N=1e6+10;
map<PII,int>mp;
int n;
int sum;
int dir[12][2]={{2018,0},{-2018,0},{0,2018},{0,-2018},{1118,1680},{-1118,1680},{1118,-1680},{-1118,-1680},{1680,1118},{-1680,1118},{1680,-1118},{-1680,-1118}};
signed main()
{
    cin>>n;
    while(n--){
        int x,y;
        cin>>x>>y;
        sum+=mp[{x,y}];
        for(int i=0;i<12;i++)
        mp[{x+dir[i][0],y+dir[i][1]}]++;
    }
    cout<<sum<<endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
extra qualification timerevent是指额外的资格和时间活动。这是一个广泛的概念,可以指任何一种能够增加个人技能和知识的额外资格或时间活动。 在职场中,个人可以通过参加专业培训课程、研讨会和工作坊来获取额外的资格和时间活动。这些活动可以为他们提供新的技能和知识,使他们在职场中更加具有竞争力。此外,个人还可以通过参加行业认证考试来获得额外的资格,这些认证可以证明他们具备特定领域的专业知识和技能。通过参与这些额外的资格和时间活动,个人可以增加自己在职场中的价值和机会。 在教育领域,学生可以通过参加额外的课外培训活动来提高自己的学术水平和技能。这些活动可以包括参加学术竞赛、科研项目、社会实践等,这些活动可以拓宽学生的眼界,培养他们的创造力和领导能力。此外,学生还可以通过参加语言培训班、艺术培训班等增加自己的技能和知识。这些额外的资格和时间活动可以为学生提供更多的机会,帮助他们在学术和职业领域取得成功。 总的来说,额外的资格和时间活动对个人和学生来说都是非常有益的。这些活动可以帮助他们提高自己的技能和知识,增加他们在职场和学术领域的竞争力。而且,额外的资格和时间活动也能为个人提供更多的机会和发展空间。因此,我们鼓励每个人都参与额外的资格和时间活动,不断提升自己。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值