Acwing 刷题

13 篇文章 0 订阅
这篇文章包含了一系列算法问题的描述和解决方案,包括寻找最小通行费路径、最大上升子序列和、怪盗基德的滑翔翼路径、登山路线选择、友好城市航道规划、导弹拦截策略以及字串变化的最少步骤。每个问题都提供了输入输出格式和示例代码。
摘要由CSDN通过智能技术生成

目录

1 1018 最低通行费

2 .1027 方格取数

3 1016 最大上升子序列

 4 1017 怪盗基德的滑翔翼

 5 1014 登山

 6 1012 友好城市

7 1010 拦截导弹

8 190 字串变化

9 1112 迷宫

10 1116 马走日


1 1018 最低通行费

一个商人穿过一个 N×NN×N 的正方形的网格,去参加一个非常重要的商务活动。

他要从网格的左上角进,右下角出。

每穿越中间 11 个小方格,都要花费 11 个单位时间。

商人必须在 (2N−1)(2N−1) 个单位时间穿越出去。

而在经过中间的每个小方格时,都需要缴纳一定的费用。

这个商人期望在规定时间内用最少费用穿越出去。

请问至少需要多少费用?

注意:不能对角穿越各个小方格(即,只能向上下左右四个方向移动且不能离开网格)。

输入格式

第一行是一个整数,表示正方形的宽度 NN。

后面 NN 行,每行 NN 个不大于 100100 的正整数,为网格上每个小方格的费用。

输出格式

输出一个整数,表示至少需要的费用。

数据范围

1≤N≤1001≤N≤100

输入样例:

5
1  4  6  8  10
2  5  7  15 17
6  8  9  18 20
10 11 12 19 21
20 23 25 29 33

输出样例:

109

样例解释

样例中,最小值为 109=1+2+5+7+9+12+19+21+33109=1+2+5+7+9+12+19+21+33。

#include<bits/stdc++.h>
using namespace std;
const int N=110;
int f[N][N],g[N][N];
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            cin>>g[i][j];
        }
    }
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(i==1&&j==1)f[i][j]=g[i][j];
            else{
                f[i][j]=1e9;
                if(i>1)f[i][j]=min(f[i][j],f[i-1][j]+g[i][j]);
                if(j>1)f[i][j]=min(f[i][j],f[i][j-1]+g[i][j]);
            }
        }
    }
    cout<<f[n][n];
    return 0;
}

没想到打挑战模式的时候被坑了 通过回顾顺利拿下

2 .1027 方格取数

设有 N×N 的方格图,我们在其中的某些方格中填入正整数,而其它的方格中则放入数字0。如下图所示:

某人从图中的左上角 A 出发,可以向下行走,也可以向右行走,直到到达右下角的 B 点。

在走过的路上,他可以取走方格中的数(取走后的方格中将变为数字0)。

此人从 A 点到 B 点共走了两次,试找出两条这样的路径,使得取得的数字和为最大。

输入格式

第一行为一个整数N,表示 N×N 的方格图。

接下来的每行有三个整数,第一个为行号数,第二个为列号数,第三个为在该行、该列上所放的数。

行和列编号从 11 开始。

一行“0 0 0”表示结束。

输出格式

输出一个整数,表示两条路径上取得的最大的和。

数据范围

N≤10N≤10

输入样例:

8
2 3 13
2 6 6
3 5 7
4 4 14
5 2 21
5 6 4
6 3 15
7 2 14
0 0 0

输出样例:

67

#include<bits/stdc++.h>
using namespace std;
int a[50][15][15],g[15][15];
int main()
{
    int n;
    cin>>n;
    int x,y,w;
    while(cin>>x>>y>>w,x!=0&&y!=0&&w!=0){
        g[x][y]+=w;
    }
    for(int k=2;k<=n+n;k++){
        for(int i1=1;i1<=n;i1++){
            for(int i2=1;i2<=n;i2++){
                int j1=k-i1,j2=k-i2;
                if(j1>=1&&j1<=n&&j2>=1&&j2<=n){
                    int t=g[i1][j1];
                    if(i1!=i2)t+=g[i2][j2];
                    a[k][i1][i2]=max(a[k][i1][i2],a[k-1][i1-1][i2-1]+t);
                    a[k][i1][i2]=max(a[k][i1][i2],a[k-1][i1][i2-1]+t);
                    a[k][i1][i2]=max(a[k][i1][i2],a[k-1][i1-1][i2]+t);
                    a[k][i1][i2]=max(a[k][i1][i2],a[k-1][i1][i2]+t);
                }
            }
        }
    }
    cout<<a[n+n][n][n];
    return 0;
}

3 1016 最大上升子序列

一个数的序列 bibi,当 b1<b2<…<bSb1<b2<…<bS 的时候,我们称这个序列是上升的。

对于给定的一个序列(a1,a2,…,aNa1,a2,…,aN),我们可以得到一些上升的子序列(ai1,ai2,…,aiKai1,ai2,…,aiK),这里1≤i1<i2<…<iK≤N1≤i1<i2<…<iK≤N。

比如,对于序列(1,7,3,5,9,4,8),有它的一些上升子序列,如(1,7),(3,4,8)等等。

这些子序列中和最大为18,为子序列(1,3,5,9)的和。

你的任务,就是对于给定的序列,求出最大上升子序列和。

注意,最长的上升子序列的和不一定是最大的,比如序列(100,1,2,3)的最大上升子序列和为100,而最长上升子序列为(1,2,3)。

输入格式

输入的第一行是序列的长度N。

第二行给出序列中的N个整数,这些整数的取值范围都在0到10000(可能重复)。

输出格式

输出一个整数,表示最大上升子序列和。

数据范围

1≤N≤10001≤N≤1000

输入样例:

7
1 7 3 5 9 4 8

输出样例:

18
#include<bits/stdc++.h>
using namespace std;
int f[1010],a[1010];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)cin>>a[i];
    for(int i=0;i<n;i++){
        f[i]=a[i];
        for(int j=0;j<i;j++){
            if(a[j]<a[i]){
                f[i]=max(f[i],f[j]+a[i]);
            }
        }
    }
    int ans=0;
    for(int i=0;i<n;i++)ans=max(ans,f[i]);
    cout<<ans;
    return 0;
}

 4 1017 怪盗基德的滑翔翼

怪盗基德是一个充满传奇色彩的怪盗,专门以珠宝为目标的超级盗窃犯。

而他最为突出的地方,就是他每次都能逃脱中村警部的重重围堵,而这也很大程度上是多亏了他随身携带的便于操作的滑翔翼。

有一天,怪盗基德像往常一样偷走了一颗珍贵的钻石,不料却被柯南小朋友识破了伪装,而他的滑翔翼的动力装置也被柯南踢出的足球破坏了。

不得已,怪盗基德只能操作受损的滑翔翼逃脱。

假设城市中一共有N幢建筑排成一条线,每幢建筑的高度各不相同。

初始时,怪盗基德可以在任何一幢建筑的顶端。

他可以选择一个方向逃跑,但是不能中途改变方向(因为中森警部会在后面追击)。

因为滑翔翼动力装置受损,他只能往下滑行(即:只能从较高的建筑滑翔到较低的建筑)。

他希望尽可能多地经过不同建筑的顶部,这样可以减缓下降时的冲击力,减少受伤的可能性。

请问,他最多可以经过多少幢不同建筑的顶部(包含初始时的建筑)?

输入格式

输入数据第一行是一个整数K,代表有K组测试数据。

每组测试数据包含两行:第一行是一个整数N,代表有N幢建筑。第二行包含N个不同的整数,每一个对应一幢建筑的高度h,按照建筑的排列顺序给出。

输出格式

对于每一组测试数据,输出一行,包含一个整数,代表怪盗基德最多可以经过的建筑数量。

数据范围

1≤K≤1001≤K≤100,
1≤N≤1001≤N≤100,
0<h<100000<h<10000

输入样例:

3
8
300 207 155 299 298 170 158 65
8
65 158 170 298 299 155 207 300
10
2 1 3 4 5 6 7 8 9 10

输出样例:

6
6
9
#include<bits/stdc++.h>
using namespace std;
int a[105],f[105],g[105];
int main()
{
    int t;
    cin>>t;
    while(t--){
        int n;
        cin>>n;
        for(int i=0;i<n;i++)cin>>a[i];
        for(int i=0;i<n;i++){
            f[i]=1;
            for(int j=0;j<i;j++){
                if(a[i]<a[j]){
                    f[i]=max(f[i],f[j]+1);
                }
            }
        }
        for(int i=0;i<n;i++){
            g[i]=1;
            for(int j=0;j<i;j++){
                if(a[i]>a[j]){
                    g[i]=max(g[i],g[j]+1);
                }
            }
        }
        int ans=0;
        for(int i=0;i<n;i++){
            ans=max(ans,max(f[i],g[i]));
        }
        cout<<ans<<endl;
    }
    return 0;
}

 5 1014 登山

五一到了,ACM队组织大家去登山观光,队员们发现山上一共有N个景点,并且决定按照顺序来浏览这些景点,即每次所浏览景点的编号都要大于前一个浏览景点的编号。

同时队员们还有另一个登山习惯,就是不连续浏览海拔相同的两个景点,并且一旦开始下山,就不再向上走了。

队员们希望在满足上面条件的同时,尽可能多的浏览景点,你能帮他们找出最多可能浏览的景点数么?

输入格式

第一行包含整数N,表示景点数量。

第二行包含N个整数,表示每个景点的海拔。

输出格式

输出一个整数,表示最多能浏览的景点数。

数据范围

2≤N≤10002≤N≤1000

输入样例:

8
186 186 150 200 160 130 197 220

输出样例:

4
#include<bits/stdc++.h>
using namespace std;
int a[1010],f[1010],g[1010];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)cin>>a[i];
    for(int i=0;i<n;i++){
        f[i]=1;
        for(int j=0;j<i;j++){
            if(a[j]<a[i])f[i]=max(f[i],f[j]+1);
        }
    }
    for(int i=n-1;i>=0;i--){
        g[i]=1;
        for(int j=n-1;j>i;j--){
            if(a[j]<a[i])g[i]=max(g[i],g[j]+1);
        }
    }
    int ans=0;
    for(int i=0;i<n;i++)ans=max(ans,f[i]+g[i]-1);
    cout<<ans;
    return 0;
}

 6 1012 友好城市

Palmia国有一条横贯东西的大河,河有笔直的南北两岸,岸上各有位置各不相同的N个城市。

北岸的每个城市有且仅有一个友好城市在南岸,而且不同城市的友好城市不相同。

每对友好城市都向政府申请在河上开辟一条直线航道连接两个城市,但是由于河上雾太大,政府决定避免任意两条航道交叉,以避免事故。

编程帮助政府做出一些批准和拒绝申请的决定,使得在保证任意两条航线不相交的情况下,被批准的申请尽量多。

输入格式

第1行,一个整数N,表示城市数。

第2行到第n+1行,每行两个整数,中间用1个空格隔开,分别表示南岸和北岸的一对友好城市的坐标。

输出格式

仅一行,输出一个整数,表示政府所能批准的最多申请数。

数据范围

1≤N≤50001≤N≤5000,
0≤xi≤100000≤xi≤10000

输入样例:

7
22 4
2 6
10 3
15 12
9 8
17 17
4 2

输出样例:

4

#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int>PII;
PII s[5010];
int f[5010];
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<n;i++)cin>>s[i].first>>s[i].second;
    sort(s,s+n);
    for(int i=0;i<n;i++){
        f[i]=1;
        for(int j=0;j<i;j++){
            if(s[i].second>s[j].second){
                f[i]=max(f[i],f[j]+1);
            }
        }
    }
    int ans=0;
    for(int i=0;i<n;i++)ans=max(ans,f[i]);
    cout<<ans;
    return 0;
}

7 1010 拦截导弹

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。

但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。

某天,雷达捕捉到敌国的导弹来袭。

由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹依次飞来的高度(雷达给出的高度数据是不大于30000的正整数,导弹数不超过1000),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入格式

共一行,输入导弹依次飞来的高度。

输出格式

第一行包含一个整数,表示最多能拦截的导弹数。

第二行包含一个整数,表示要拦截所有导弹最少要配备的系统数。

数据范围

雷达给出的高度数据是不大于 30000 30000 的正整数,导弹数不超过 1000 1000。

输入样例:

389 207 155 300 299 170 158 65

输出样例:

6
2

 当然这是noip的原题但是数据没被加强也就是暴力可以做 各大平台的数据已经加强后面我再想想怎么优化

#include<bits/stdc++.h>
using namespace std;
int a[1010],f[1010],g[1010];
int main()
{
    int n=0;
    while(cin>>a[n])n++;
    int ans=0;
    for(int i=0;i<n;i++){
        f[i]=1;
        for(int j=0;j<i;j++){
            if(a[j]>=a[i])f[i]=max(f[i],f[j]+1);
        }
        ans=max(ans,f[i]);
    }
    cout<<ans<<endl;
    int cnt=0;
    for(int i=0;i<n;i++){
        int k=0;
        while(k<cnt&&g[k]<a[i])k++;
        g[k]=a[i];
        if(k>=cnt)cnt++;
    }
    cout<<cnt<<endl;
    return 0;
}

8 190 字串变化

已知有两个字串 A�, B� 及一组字串变换的规则(至多 6 个规则):

A1→B1�1→�1

A2→B2�2→�2

规则的含义为:在 A� 中的子串 A1�1 可以变换为 B1�1、A2�2 可以变换为 B2…�2…。

例如:A�=abcd B�=xyz

变换规则为:

abc →→ xu ud →→ y y →→ yz

则此时,A� 可以经过一系列的变换变为 B�,其变换的过程为:

abcd →→ xud →→ xy →→ xyz

共进行了三次变换,使得 A� 变换为 B�。

输入格式

输入格式如下:9

A� B�
A1�1 B1�1
A2�2 B2�2
… …

第一行是两个给定的字符串 A� 和 B�。

接下来若干行,每行描述一组字串变换的规则。

所有字符串长度的上限为 2020。

输出格式

若在 1010 步(包含 1010 步)以内能将 A� 变换为 B� ,则输出最少的变换步数;否则输出 NO ANSWER!

输入样例:

abcd xyz
abc xu
ud y
y yz

输出样例:

3

一道双向广搜的题 

#include<bits/stdc++.h>
using namespace std;
int n;
string a[10],b[10];

int extend(queue<string>&q,unordered_map<string,int>&da,unordered_map<string,int>&db,string a[],string b[])
{
    string t=q.front();
    q.pop();
    for(int i=0;i<t.size();i++){
        for(int j=0;j<n;j++){
            if(t.substr(i,a[j].size())==a[j]){
                string state=t.substr(0,i)+b[j]+t.substr(i+a[j].size());
                if(db.count(state))return da[t]+1+db[state];
                if(da.count(state))continue;
                da[state]=da[t]+1;
                q.push(state);
            }
        }
    }
    return 11;
}
int bfs(string A,string B)
{
    if(A==B)return 0;
    queue<string>qa,qb;
    unordered_map<string,int>da,db;
    qa.push(A),da[A]=0;
    qb.push(B),db[B]=0;
    while(qa.size()&&qb.size())
    {
        int t;
        if(qa.size()<qb.size())t=extend(qa,da,db,a,b);
        else t=extend(qb,db,da,b,a);
        if(t<=10)return t;
    }
    return 11;
}
int main()
{
    string A,B;
    cin>>A>>B;
    while(cin>>a[n]>>b[n])n++;
    int u=bfs(A,B);
    if(u>10)cout<<"NO ANSWER!\n";
    else cout<<u<<endl;
    return 0;
}

9 1112 迷宫

一天Extense在森林里探险的时候不小心走入了一个迷宫,迷宫可以看成是由 n∗n�∗� 的格点组成,每个格点只有2种状态,.#,前者表示可以通行后者表示不能通行。

同时当Extense处在某个格点时,他只能移动到东南西北(或者说上下左右)四个方向之一的相邻格点上,Extense想要从点A走到点B,问在不走出迷宫的情况下能不能办到。

如果起点或者终点有一个不能通行(为#),则看成无法办到。

注意:A、B不一定是两个不同的点。

输入格式

第1行是测试数据的组数 k�,后面跟着 k� 组输入。

每组测试数据的第1行是一个正整数 n�,表示迷宫的规模是 n∗n�∗� 的。

接下来是一个 n∗n�∗� 的矩阵,矩阵中的元素为.或者#

再接下来一行是 4 个整数 ha,la,hb,lbℎ�,��,ℎ�,��,描述 A� 处在第 haℎ� 行, 第 la�� 列,B� 处在第 hbℎ� 行, 第 lb�� 列。

注意到 ha,la,hb,lbℎ�,��,ℎ�,�� 全部是从 0 开始计数的。

输出格式

k行,每行输出对应一个输入。

能办到则输出“YES”,否则输出“NO”。

数据范围

1≤n≤1001≤�≤100

输入样例:

2
3
.##
..#
#..
0 0 2 2
5
.....
###.#
..#..
###..
...#.
0 0 4 0

输出样例:

YES
NO

#include<bits/stdc++.h>
using namespace std;
char g[105][105];
bool st[105][105];
int xa,xb,ya,yb;
int n;
int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};
bool dfs(int x,int y)
{
    if(g[x][y]=='#')return false;
    if(x==xb&&y==yb)return true;
    st[x][y]=true;
    for(int i=0;i<4;i++){
        int a=x+dx[i],b=y+dy[i];
        if(a<0||a>=n||b<0||b>=n)continue;
        if(st[a][b])continue;
        if(dfs(a,b))return true;
    }
    return false;
}
int main()
{
    int t;
    cin>>t;
    while(t--){
        cin>>n;
        for(int i=0;i<n;i++)cin>>g[i];
        memset(st,0,sizeof st);
        cin>>xa>>ya>>xb>>yb;
        if(dfs(xa,ya))cout<<"YES\n";
        else cout<<"NO\n";
    }

    return 0;
}

10 1116 马走日

马在中国象棋以日字形规则移动。

请编写一段程序,给定 n∗m 大小的棋盘,以及马的初始位置 (x,y),要求不能重复经过棋盘上的同一个点,计算马可以有多少途径遍历棋盘上的所有点。

输入格式

第一行为整数 T,表示测试数据组数。

每一组测试数据包含一行,为四个整数,分别为棋盘的大小以及初始位置坐标 n,m,x,y。

输出格式

每组测试数据包含一行,为一个整数,表示马能遍历棋盘的途径总数,若无法遍历棋盘上的所有点则输出 0。

数据范围

1≤T≤9,
1≤m,n≤9,
1≤n×m≤28,
0≤x≤n−1,
0≤y≤m−1

输入样例:

1
5 4 0 0

输出样例:

32

#include<bits/stdc++.h>
using namespace std;
int ans,n,m;
bool st[15][15];
int dx[8]={-2,-1,1,2,2,1,-1,-2};
int dy[8]={1,2,2,1,-1,-2,-2,-1};
void dfs(int x,int y,int cnt)
{
    if(cnt==n*m){
        ans++;
        return ;
    }
    st[x][y]=true;
    for(int i=0;i<8;i++){
        int a=x+dx[i],b=y+dy[i];
        if(a<0||a>=n||b<0||b>=m)continue;
        if(st[a][b])continue;
        dfs(a,b,cnt+1);
    }
    st[x][y]=false;
}
int main()
{
    int t;
    cin>>t;
    while(t--){
        int x,y;
        cin>>n>>m>>x>>y;
        ans=0;
        dfs(x,y,1);
        cout<<ans<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值