HDU 2018-2099题记录

该博客汇总了多个算法题的解题思路,涉及动态规划、排序算法、贪心算法等。如母牛故事用动态规划,绝对值排序用插入/冒泡排序和双指针,发工资用贪心算法。还包含递推、递归题,以及进制转换、二维数组使用等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

2018-母牛的故事

动态规划

2020-绝对值排序

1.插入排序/冒泡排序

2.双指针

2021-发工资咯

贪心:每次选择最大面值,扣到0时的cnt即为发放该工资所需最小数量

2022-海选女主角

遍历二维数组

2023-求平均值

二维数组的基本使用

2024-C语言合法标识符

合法标识符定义

2025-查找最大元素

主要是解决字符串输入问题

2028-最小公倍数(最大公约数变体)

a和b的最小公倍数:a * b / gcd(a,b)

2030-汉字统计

清楚汉字编码的特点:汉字码是小于0。并且一个汉字占两个字节(每一个字节均小于0)。

2031-进制转换

进制转换模版

2034-人见人爱A-B

set容器的应用

2036-改革春风吹满地

2037-今年暑假不AC

2040-亲和数

数学:公约数问题

2041-超级楼梯

递推题

2044-小蜜蜂

递推题

2045-RPG难题

递推题

2046-骨骼铺方格

递推题

2047-EOF

递归题

2051-进制转换

十进制转二进制

2057-A+B again

笨比做法:转十进制再转十六进制

2064-汉诺塔3

递推式,把前n-1层看成一个整体移动,故f[n] = 3 * f[n-1] + 2;

 2066-一个人的旅行

Dijkstra:这里可以把人看做0号顶点,到相邻城市的距离为0

2067-小兔的棋盘

二维数组的递推式(二维超级楼梯):要使得路径最小,每次仅往右或往下(好兔不走回头路)

2072-单词数

利用set数据不重复的特性。注意:要考虑多个空格的边界条件

 2074-叠框

每次以上一行为基准翻转数组,然后对称输出

2076-夹角计算1

推导数学公式

2077-汉诺塔4

递推式:先求出到相邻杆子的最小移动次数

2079-选课时间

DFS排列组合(去重+剪枝)

2080-夹角计算2

atan求角度,注意对 正负四象限 两种情况区分讨论,本题以x正方向为基准

2081-手机短号

水题,字符串输出

2082-找单词

多重背包问题,注意:边界条件是f[i][0] = 1;

2083-简易版最短距离

贪心:站在中间(左右房子数量相同),每次路程即为两端点最短距离(双指针)

2084 -数塔

最大值DP问题

2085-核反应堆

观察规律,找到公式即可

2087-剪花布条

本题数据量小,可直接枚举n²,若数据量大,考虑KMP

2089-不要62

把数字转为字符串,并判断是否符合题意

2091-空三角形

观察位置规律,写出公式即可

2093-考试排名

结构体/输入/输出/重载比较运算

2092-整数解

数学问题

2094-产生冠军

输入样例等价为一个有向图,当仅有一个结点入度为0时,产生冠军

2095-find presen

map容器的应用

2097-Sky数

进制转换问题

2099-整数的尾除

分析规律:补上 余数与除数的差额 ,即可得到当前最小可被整除的数



2018-母牛的故事

动态规划

第N年的母牛个数等于前一年的母牛数+四年前的母牛数

#include <cstdio>
​
using namespace std;
​
​
int main(void)
{
    int  n,m, sum1,sum2;
    string s;
    int arr[60];
    while(scanf("%d",&n)!=EOF)
    {
        if (n == 0)break;
        if (n <= 4) {
            printf("%d\n",n);
            continue;
        }
        arr[1] = 1;
        arr[2] = 2;
        arr[3] = 3;
        arr[4] = 4;
        for (int i = 5; i <= n; ++i) {
            arr[i] = arr[i-1] + arr[i-3];
        }
        printf("%d\n",arr[n]);
    }
​
    return 0;
}
 

2020-绝对值排序

1.插入排序/冒泡排序

每插入一个数据,不断向前调整到合适的位置

#include <iostream>
#include <cstdio>
​
using namespace std;
​
​
static int arr[100];
​
void swap (int x, int y)    //形参为数组索引
{
    int t = arr[x];
    arr[x] = arr[y];
    arr[y] = t;
}
​
void insert_sort (int x, int index)
{
    arr[index] = x;
    for (int i = index; i > 0; i--) {
        int abs_x = arr[i] > 0 ? arr[i] : -arr[i];
        int abs_y = arr[i-1] > 0 ? arr[i-1] : -arr[i-1];
        if (abs_x > abs_y) swap(i,i-1);
        else return;
    }
}
​
​
int main(void)
{
    int  n, num;
    while(scanf("%d",&n) != EOF)
    {
        if (n == 0) break;
        for (int i = 0; i < n; ++i) {
            scanf("%d",&num);
            insert_sort(num,i);
        }
​
        for (int i = 0; i < n; ++i) {
            i == (n-1) ? printf("%d\n",arr[i]) : printf("%d ",arr[i]);
        }
    }
    return 0;
}
 

2.双指针

i指向对头,j指向队尾,每次输出较大的数。

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
const int N = 110;
int a[N];

int main()
{
    int n;
    while(scanf("%d", &n))
    {
        if(!n) return 0;
        for (int i = 1; i <= n; i ++ ) scanf("%d", &a[i]);
        sort(a+1,a+n+1);
        for(int i = 1, j = n; i <= j; )
        {
            if(i == j) printf("%d\n",a[i++]);
            else if(abs(a[i]) > abs(a[j])) printf("%d ",a[i++]);
            else printf("%d ",a[j--]);
        }
    }
    
    return 0;
}

2021-发工资咯

贪心:每次选择最大面值,扣到0时的cnt即为发放该工资所需最小数量

#include <iostream>
#include <cstdio>

using namespace std;


int main(void)
{
    int  n, money, sum;
    while(scanf("%d",&n) != EOF)
    {
        if (n == 0) break;
        sum = 0;
        for (int i = 0; i < n; ++i) {
            int cnt = 0;
            scanf("%d",&money);
            while (money)
            {
                if (money - 100 >= 0) money -= 100;
                else if (money - 50 >= 0) money -= 50;
                else if (money - 10 >= 0) money -= 10;
                else if (money - 5 >= 0) money -= 5;
                else if (money - 2 >= 0) money -= 2;
                else  money -= 1;
                cnt ++;
            }
            sum += cnt;
        }
        printf("%d\n",sum);
    }
    return 0;
}

2022-海选女主角

遍历二维数组

#include <iostream>
#include <cstdio>

using namespace std;

int m,n,r,c;
double val = 0;
double x;


double get_abs (double a){
    return a > 0 ? a : -a;
}


int main(void)
{

    while(scanf("%d%d",&m,&n) != EOF)
    {
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                scanf("%lf",&x);
                if (get_abs(x) > get_abs(val))
                {
                    val = x;
                    r = i;
                    c = j;
                }

            }
        }
        printf("%d %d %.0f\n",r+1,c+1,val);
        val = 0;
    }
    return 0;
}

2023-求平均值

二维数组的基本使用

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 60, M = 10;
double s[N][M], cnt;

void init(int n, int m)
{
    for (int i = 1; i <= N; i ++ )
        for (int j = 1; j <= M; j ++ )
            s[i][j] = 0;
            
    cnt = 0;
}

int main()
{
    int n, m;
    while(cin >> n >> m)
    {
        init(n, m);
        for (int i = 1; i <= n; i ++ )
        {
            double sum = 0;
            for (int j = 1; j <= m; j ++ )
            {
                double k;
                cin >> k;
                s[i][j] = k;
                s[n+1][j] += k; // 第n+1行记录每科成绩平均分
                sum += k;
            }
            s[i][m+1] = sum / m; // 第m+1列记录学生平均分 
        }
        for (int i = 1; i <= m; i ++ ) s[n+1][i] /= n; 
        
        for (int i = 1; i <= n; i ++ ) printf("%.2f ",s[i][m+1]);//学生的平均分
        puts("");
        for (int i = 1; i <= m; i ++ ) printf("%.2f ",s[n+1][i]);//课程分
        puts("");
        
        for (int i = 1; i <= n; i ++ )
        {
            int w = 0;
            for (int j = 1; j <= m; j ++ )
            {
                if(s[i][j] >= s[n+1][j]) w++;
            }
            if(w == m) cnt++;
        }
        cout << cnt << endl;
        puts("");
    }
   
    return 0;
}

2024-C语言合法标识符

这里强调字符串输入格式

	scanf("%d%",&n);
        getchar();   
	//等价于scanf("%d%*c",&n); 缓冲区为 3\n  二者都是拿走\n

%*c 的标准用法是什么。它的意义何在?
我所知道的是它经常出现在例如
cscanf("%s%*c",&a);语句中。
   
/*
你的例子中的%*c的作用是读入'\n',即回车符,否则后面读入的将是'\n'。

"*"表示该输入项读入后不赋予任何变量,即跳过该输入值。
*/

合法标识符定义

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

static int n;
static char s[60];

int getlen (char *str)
{
    int cnt;
    for (int i = 0; str[i] != '\0' ; ++i)
    {
        cnt++;
    }
    return cnt;
}

int process (char *str)
{
    if (str[0] - 'a' >= 0 && 'z'-str[0] >=0) ;
    else if (str[0] - 'A' >= 0 && 'Z'-str[0] >=0) ;
    else if (str[0] == '_') ;
    else return 0;
    if (str[0]-'0' )
        for (int i = 1; str[i] != '\0' ; ++i) {
        if (str[i] - 'a' >= 0 && 'z'-str[i] >=0) continue;
        else if (str[i] - 'A' >= 0 && 'Z'-str[i] >=0) continue;
        else if (str[i] - '0' >= 0 && '9'-str[i] >=0) continue;
        else if (str[i] == '_') continue;
        else return 0;
    }
    return 1;
}

int main(void)
{


    scanf("%d%",&n);
    getchar();   //等价于scanf("%d%*c",&n); 缓冲区为 3\n  二者都是拿走\n
    while(n--)
    {
        cin.getline(s, 60);
        //printf("%s\n", s);
        process(s) ? printf("yes\n") : printf("no\n");
    }
    return 0;
}

2025-查找最大元素

主要是解决字符串输入问题

关于使用 gets() 函数需要注意:使用 gets() 时,系统会将最后“敲”的换行符从缓冲区中取出来,然后丢弃,所以缓冲区中不会遗留换行符。这就意味着,如果前面使用过 gets(),而后面又要从键盘给字符变量赋值的话就不需要吸收回车清空缓冲区了,因为缓冲区的回车已经被 gets() 取出来扔掉了。

原文链接:gets函数,C语言gets函数详解_gets()的功能-优快云博客

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

static char s[120];
static char m;


int main(void)
{
    while(gets(s))
    {
        m = 'a';
        for (int i = 0; s[i] != '\0'; ++i) {
            if (s[i] > m)   m = s[i];
        }
        for (int i = 0; s[i] != '\0'; ++i) {
            if (s[i] == m) printf("%c(max)",s[i]);
            else printf("%c",s[i]);
        }
        printf("\n");
    }



    return 0;
}

2028-最小公倍数(最大公约数变体)

a和b的最小公倍数:a * b / gcd(a,b)

故三个数的最小公倍数:先求前两个的最小公倍数c,再拿c和第三个数求最小公倍数。n个以此类推。

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;

LL gcd (LL a, LL b)
{
    return b ? gcd(b, a % b) : a;
}

int main()
{
    LL n, a, b, c;
    while (cin >> n)
    {
        if(n == 1){
            cin >> a;
            cout << a << endl;
        }
        else {
            cin >> a >> b;
        LL pre = a * b / gcd(a, b);
        for (int i = 3; i <= n; i ++ )
        {
            cin >> c;
            pre = pre * c / gcd(pre, c);
        }
        cout << pre << endl;
        }
    }
    return 0;
}

2030-汉字统计

清楚汉字编码的特点:汉字码是小于0。并且一个汉字占两个字节(每一个字节均小于0)。

注意:getline(cin,s)对应头文件#include<string>

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <string>

using namespace std;


int main()
{
    int n;
    cin >> n;
    getchar();
    while (n -- )
    {
        string s;
        getline(cin,s);
        int cnt = 0;
        for (int i = 0; i < s.size(); i++ )
            if(s[i] < 0) cnt++;
        cout << cnt/2 << endl;
    }
    return 0;
}

2031-进制转换

进制转换模版

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>

using namespace std;

char itoc (int x)
{
    if(x <= 9) return x + '0';
    return x + 'A' - 10;
}

int main()
{
    int n, b, abs_n;
    while(cin >> n >> b)
    {
        abs_n = n < 0 ? -n : n;
        string res;
        while(abs_n) res += itoc(abs_n % b), abs_n /= b;
        
        if(n < 0) res += "-";
        reverse(res.begin(), res.end());
        cout << res << endl;
    }
    
    return 0;
}

2034-人见人爱A-B

set容器的应用

#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>

using namespace std;

int n, m;

int main()
{
    while (cin >> n >> m)
    {
        set<int> a;
        if(n==0 && m==0) break;
        for (int i = 1; i <= n; i ++ )
        {
            int num;
            cin >> num;
            a.insert(num);
        }
        for (int i = 1; i <= m; i ++ )
        {
            int num;
            cin >> num;
            if(a.find(num) != a.end()) a.erase(num);
        }
        if (!a.size()) cout << "NULL" << endl;
        else {
            for (auto w : a) cout << w << " ";
            puts("");
        }
    }
    
    return 0;
}

2036-改革春风吹满地

2037-今年暑假不AC

2040-亲和数

数学:公约数问题

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int get_gys(int k)
{
    int sum = 0;
    for (int i = 1; i <= k/i; i ++ )
    {
        if(k % i == 0)
        {
            sum += i;
            if(i != k/i) sum += k/i;
        }
    }
    return sum;
}

int main()
{
    int n;
    cin >> n;
    while (n -- )
    {
        int a, b;
        cin >> a >> b;
        if(get_gys(a) == get_gys(b)) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    
    return 0;
}

2041-超级楼梯

递推题

由题目可知,每次只能走一级或两级。 因此从第一级走上第二级只能走一步,只有1种走法。 从第一级走上第三级,可以从第一级直接走两步,也可以从第二级走一步。有2种走法 走上第n级,可以从第n-1级走一步上来,也可以从第n-2级走两步上来。 即: f(2) = 1 f(3) = 2 f(n) = f(n-1) + f(n-2) (n > 3) 是一个斐波那契函数。

#include <iostream>
#include <cstdio>

using namespace std;

static int n;
static long long arr[41];
int m;

int main(void)
{
    arr[1] = 1;
    arr[2] = 1;
    scanf("%d",&n);
    for (int i = 3; i <= 40; ++i) {
        arr[i] = arr[i-1] + arr[i-2];
    }
    while(n--)
    {
        scanf("%d",&m);
        if (m <=2) {
            if (m==1)   printf("%d\n",0);
            else printf("%d\n",1);
            continue;
        }
        printf("%d\n",arr[m]);

    }
    return 0;
}

2044-小蜜蜂

递推题

其中从3到6等价于从1到4

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;

static int n;
static long long arr[60];
int a,b;

int main(void)
{
    arr[2] = 1;
    arr[3] = 2;
    for (int i = 4; i < 51; ++i) {
        arr[i] = arr[i-1] + arr[i-2];
    }
    scanf("%d",&n);

    while(n--)
    {
        scanf("%d%d",&a,&b);
        int d = b-a;

        printf("%lld\n",arr[1+d]);
    }
    return 0;
}

2045-RPG难题

递推题

其实这道题的解法就是站在涂色后的最后一块,思考前一块是怎么涂色的就可以了,比如 如果最后一块的前一块是与第一块颜色不同的情况,则最后一块只有一种颜色可以涂,其方法的数目等于f(n-1),而当最后一块前面一块的颜色与第一块相同时,则倒数第三块一定与第一块的颜色不同,则涂到倒数第三块有f(n-2)方法,到倒数第二块有f(n-2)种方法,最后一块则有 f(n-2)2种方法,由此可以的出递推的关系式 f(n)=f(n-1)+2 * f(n-2); 题目中给出的范围不大,可以先采取打表的方法给出所有的结果,再输出即可。

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 51;
long long f[N];

int main()
{
    int n;
    f[1] = 3, f[2] = 6, f[3] = 6;
    for (int i = 4; i < N; i ++ )
        f[i] = f[i-1] + f[i-2] * 2;
    
    while (cin >> n)
    {
        cout << f[n] << endl;
    }
    
    return 0;
}

2046-骨骼铺方格

递推题

从图中也可以观察出来,第N张牌的排列可以又N-1张牌的排列再在末尾加上一张竖的牌。这样依然合法。 也可以在N-2张合法排列的牌后面加上两张横着放的牌(如果竖着放就和上面一种重复了)。

所以f(n) = f(n-1) + f(n-2) 即又是一个斐波那契数列。

#include <cstdio>

using namespace std;

static int n;
static long long arr[51];

int main(void)
{
    arr[1] = 1;
    arr[2] = 2;
    arr[3] = 3;
    for (int i = 4; i < 51; ++i) {
        arr[i] = arr[i-1] + arr[i-2];
    }

    while(scanf("%d",&n) != EOF)
    {

        printf("%lld\n",arr[n]);
    }
    return 0;
}

2047-EOF

递归题

分为两种情况 当第n个是“O”时,依据限制条件,那么第n-1个不能为“O”,那n-1不为“O”就有两种情况了,即为“E”或者“F”,所以这种情况有f(n-2)2个 当第n个不为“O”时,与第一步相同,也有两种情况,即为“E”或者“F”,所以这种情况有f(n-1)2个. 递推公式:f(n)=f(n-2) * 2+f(n-1) * 2

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 41;
long long f[N];

int main()
{
    int n;
    f[1] = 3, f[2] = 8;
    for (int i = 3; i < N; i ++ )
        f[i] = f[i-1]* 2 + f[i-2] * 2;
    
    while (cin >> n)
    {
        cout << f[n] << endl;
    }   
    return 0;
}

原文链接:杭电ACM 2047 - 阿牛的EOF牛肉串(解题思路与详细分析)_阿牛的牛肉串题解-优快云博客

2051-进制转换

十进制转二进制

模版题

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

char itoc (int x)
{
    if(x <= 9) return x + '0';
    else return 'A' + x - 10;
}

int main()
{
    int n;
    while (cin >> n)
    {
        string s;
        while(n) s += itoc(n % 2), n /= 2;
        reverse(s.begin(), s.end());
        cout << s << endl;
    }
    
    return 0;
}

2057-A+B again

笨比做法:转十进制再转十六进制

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

string s[100];

long long ctoi (char c)
{
    if(c >= '0' && c <= '9') return c - '0';
    else if(c >= 'A' && c <= 'Z') return c - 'A' + 10;
    else return c - 'a' + 10;
}

char itoc (long long x)
{
    if(x <= 9 && x >= 0) return x + '0';
    else return x - 10 + 'A';
}
int main()
{
    string s1, s2;
    while (cin >> s1 >> s2 )
    {
        long long len1 = s1.size(), len2 = s2.size();
        long long i1 = 0, i2 = 0;
        if(s1[0] == '+' || s1[0] == '-') i1++;
        if(s2[0] == '+' || s2[0] == '-') i2++;
        
        long long n1 = 0, n2 = 0;
        for (int i = i1; i < len1 ; i ++ ) n1 = n1 * 16 + ctoi(s1[i]);
        for (int i = i2; i < len2 ; i ++ ) n2 = n2 * 16 + ctoi(s2[i]);
        
        long long ans = 0;
        if(s1[0] != '-' && s2[0] != '-') ans = n1 + n2;
        if(s1[0] != '-' && s2[0] == '-') ans = n1 - n2;
        if(s1[0] == '-' && s2[0] != '-') ans = -n1 + n2;
        if(s1[0] == '-' && s2[0] == '-') ans = -n1 - n2;
        
        if (ans == 0) cout << 0 << endl;
        else
        {
            if(ans < 0)
            {
                cout << "-";
                ans = -ans;
            }
            string s;
            while(ans) s += itoc(ans % 16), ans /= 16;
            reverse(s.begin(), s.end());
            cout << s << endl;
        }
        
    }
    
    return 0;
}

2064-汉诺塔3

递推式,把前n-1层看成一个整体移动,故f[n] = 3 * f[n-1] + 2;

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 36;
long long hnt[N];

void init_hnt()
{
    hnt[1] = 2;
    for (int i = 2; i <= 35; i ++ )
    {
        hnt[i] = 3*hnt[i-1] + 2;
    }
}

int main()
{
    int n;
    init_hnt();
    while(cin >> n)
    {
        cout << hnt[n] << endl;
    }
    
    return 0;
}

 2066-一个人的旅行

Dijkstra:这里可以把人看做0号顶点,到相邻城市的距离为0

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1010;

int g[N][N];
int dist[N], st[N], city[N], aim[N];
int a, b, val, t, s, d, n;

void init()
{
    memset(g, 0x3f, sizeof g);
    memset(dist, 0x3f, sizeof dist);
    memset(st, 0, sizeof st);
}

void dijkstra() //从k到n的最短距离, 其中1 <= k <=n .
{
    //dist[k] = 0;
    for (int i = 0; i < n; i ++ )
    {
        int t = -1;
        for (int j = 1; j <= n; j ++ )
            if(!st[j] && (t == - 1 || dist[t] > dist[j]) )
                t = j;
        st[t] = 1;
        for (int j = 1; j <= n; j ++ )
            dist[j] = min(dist[j], dist[t] + g[t][j]);
    }
}

int main()
{
    while (cin >> t >> s >> d)
    {
        init();
        
        while (t -- )
        {
            cin >> a >> b >> val;
            if(a != b)
            {
                g[a][b] = g[b][a] = min(g[a][b], val);
                n = max(n, b);
                n = max(n, a);
            }
        }
        int k;
        for (int i = 1; i <= s; i++) 
        {
            cin >> k;
            dist[k] = 0;
            g[0][k] = g[k][0] = 0;
        }
        
        for (int i = 1; i <= d; i++) cin >> aim[i];
        dijkstra();
        int ans = 1e9;
        for (int j = 1; j <= d; j ++ )
            ans = min(ans, dist[aim[j]]);
        cout << ans << endl;
    }
    return 0;
}

2067-小兔的棋盘

二维数组的递推式(二维超级楼梯):要使得路径最小,每次仅往右或往下(好兔不走回头路)

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 36;
long long dp[N][N];
int k, cnt;

void init_dp(int n)
{
    for (int i = 0; i <= n; i ++ ) dp[0][i] = 1;
    for (int i = 1; i <= n; i ++ )
    {
        for (int j = i; j <= n; j ++ )
        {
            if(i == j) dp[i][j] = dp[i-1][j];
            else dp[i][j] = dp[i][j-1] + dp[i-1][j];
        }
    }
}

int main()
{
    init_dp(35);
    while(cin >> k)
    {
        if(k==-1) break;
        printf("%d %d %lld\n",++cnt,k,dp[k][k] << 1);
    }
    
    return 0; 
}

2072-单词数

利用set数据不重复的特性。注意:要考虑多个空格的边界条件

#include <iostream>
#include <string>
#include <algorithm>
#include <set>

using namespace std;

int main()
{
    set<string> v;
    string s, word;
    while(getline(cin,s))
    {
        if(s == "#") return 0;
        v.clear();
        int len = s.size();
        for (int i = 0; i < len; i ++ )
        {
            if(s[i] == ' ') 
            {
                if(word.size()) {
                    v.insert(word);
                    word = "";
                }
            }
            else word += s[i];
        }
        if(word.size()) {
            v.insert(word);
            word = "";
        }
        cout << v.size() << endl;
    }
    
    return 0;
}

 2074-叠框

每次以上一行为基准翻转数组,然后对称输出

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 81;
char g[N][N];
int n;
char zx, ww;

void write(int x, int a, int b) //写x行第a列到第b列
{
    char c;
    c = g[x-1][a] == zx ? ww : zx;
    for (int i = 1; i < a; i ++ ) g[x][i] = g[x-1][i];
    for (int i = a; i <= b; i ++ ) {
        g[x][i] = c;
    }
    for (int i = b+1; i <= n; i ++ ) g[x][i] = g[x-1][i];
}

int main()
{
    while(cin >> n >> zx >> ww)
    {
        if(n == 1)
        {
            cout << zx << endl;
            puts("");
        }
        
        else {
            int mid = (n + 1) >> 1;
            char first;
            first = mid % 2 == 0 ? ww : zx;
            for (int i = 1; i <= n; i ++ ) 
                g[1][i] = first;
            for (int i = 2; i <= mid; i ++ )
                write(i, i, n-i+1);
            
            g[1][1] = ' ';
            g[1][n] = ' ';
            for (int i = 1; i <= mid; i ++ )
            {
                for (int j = 1; j <= n; j ++ )
                {
                    cout <<g[i][j] << "";
                }
                cout << endl;
            }
            //对称输出
            for (int i = mid-1; i >= 1; i -- )
            {
                for (int j = 1; j <= n; j ++ )
                {
                    cout <<g[i][j] << "";
                }
                cout << endl;
            }
            puts("");
        }
    }
    return 0;
}

2076-夹角计算1

推导数学公式

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;

const int N = 510;
double hour_add = 0, min_add = 0, hour_angle = 0, min_angle = 0, d = 0;
// 时针30度一格, 分针6度一格
// 时钟一格 秒钟3600转
// 分钟一格秒钟60
int main()
{
    int n;
    double hour, mi, sec;

    cin >> n;
    while (n -- )
    {
        hour_angle = 0, min_angle = 0, d = 0;
        cin >> hour >> mi >> sec;
        if(hour >= 12) hour = hour - 12;
        //秒钟转 从而分钟转 从而时钟转
        hour_angle = hour * 30 + (mi * 60  + sec) / 3600* 30; //时钟一格 秒钟3600
        min_angle = mi * 6 + sec / 60 * 6;//分钟一格 秒钟60
       
        d = hour_angle - min_angle;
        d = abs(d);
        if(d > 180) d = 360-d;
        cout << (int)d << endl;
    }
    return 0;
}

2077-汉诺塔4

递推式:先求出到相邻杆子的最小移动次数

#include <iostream>
#include <cstring>
#include <algorithm>

typedef long long LL;

using namespace std;

const int N = 21;
LL dp[N]; //把n个移动到相邻盘

void init()
{
    dp[1] = 1;
    dp[2] = 4;
    for (int i = 3; i < N; i ++ )
        dp[i] = dp[i-1]*3 + 1;
}

int main()
{
    init();
    int n, k;
    cin >> n;
    while (n -- )
    {
        cin >> k;
        cout << dp[k-1]*2 + 2 << endl;
    }
    
    return 0;
}

2079-选课时间

DFS排列组合(去重+剪枝)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <queue>

using namespace std;
int s[9], cnt;

void init()
{
    for (int i = 1; i <= 8; i ++ ) s[i] = 0;
    cnt = 0;
}

void dfs(int x,int idx)
{
    if(!x) {
        cnt++;
        return;
    }
    for (int i = idx; i <= 8; i ++ )
    {
        if(!s[i]) continue;
        if(x-i < 0) continue;
        s[i]--;
        dfs(x-i,i);
        s[i]++;
    }
}

int main()
{
    int t;
    cin >> t;
    while (t--) 
    {
        init();
        int n, k;
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= k; i ++ )
        {
            int a, b;
            scanf("%d%d", &a, &b);
            s[a] = b;
        }
        for (int i = 1; i <= 8; i ++ )
        {
            if(!s[i]) continue;
            if(n-i < 0) continue;
            s[i]--;
            dfs(n-i,i);
            s[i]++;
        }
        cout << cnt << endl;
    }
    
    return 0;
}

2080-夹角计算2

atan求角度,注意对 正负四象限 两种情况区分讨论,本题以x正方向为基准

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define PII 3.1415926535898

double x_1, y_1, x_2, y_2, d;
// 时针30度一格, 分针6度一格
// 时钟一格 秒钟3600转
// 分钟一格秒钟60

double get_angle(double x, double y)
{
    if(x == 0) return y > 0 ? 90: 270;
    else if(y == 0) return x > 0 ? 0: 180;
    double k = atan(y / x) / PII * 180;
    k = abs(k);
    if(x > 0 && y >= 0) return k;
    else if(x < 0 && y <= 0) return k + 180;
    else if(x > 0 && y <= 0) return 360 - k;
    else if(x < 0 && y >= 0) return 180 - k;
}

int main()
{
    int n;
    cin >> n;
    while (n -- )
    {
        double angle1, angle2;
        cin >> x_1 >> y_1 >> x_2 >> y_2;
        angle1 = get_angle(x_1,y_1);
        angle2 = get_angle(x_2,y_2);
        
        double d = abs(angle1-angle2);
        if(d > 180) d -= 180;


        printf("%.2f \n",d);
    }
    return 0;
}

2081-手机短号

水题,字符串输出

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;

int main()
{
    int n;
    cin >> n;
    getchar();
    for (int i = 1; i <= n; i ++ )
    {
        string s;
        getline(cin, s);
        int len = s.size();
        cout << '6';
        for (int i = 6; i < len; i ++ )
            cout << s[i];
        puts("");
    }    
    return 0;
}

2082-找单词

多重背包问题,注意:边界条件是f[i][0] = 1;

f[i][j]表示前i个字母组成价值为j的最大单词数量

j = 0 时,意味着只有一种情况

可以优化为滚动数组

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 110;
int v[N], w[N], s[N];
int f[N][N];

int main()
{
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i] >> s[i];
    
    for (int i = 1; i <= n; i ++ ) 
    {
        for (int j = 0; j <= m; j ++ )
        {
            f[i][j] = f[i-1][j];
            for (int k = 1; k <= s[i]; k ++ )
                if(j >= k * v[i]) f[i][j] = max(f[i][j], f[i-1][j - k * v[i]] + k * w[i]);
        }
    }
    cout << f[n][m];
    
    return 0;
}

2083-简易版最短距离

贪心:站在中间(左右房子数量相同),每次路程即为两端点最短距离(双指针)

#include <iostream>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;

const int N = 510;
int f[N], d;

int main()
{
    int m, n;
    cin >> m;
    for (int i = 1; i <= m; i ++ )
    {
        cin >> n;
        d = 0;
        for (int j = 1; j <= n; j ++ ) cin >> f[j];
        sort(f+1,f+n+1);
        int a, b;
        for (a = 1, b = n; a < b; a++, b--)
            d += f[b] - f[a];
            
        cout << d << endl;
    }
    
    
    return 0;
}

2084 -数塔

最大值DP问题

自上而下,保存每一个结点的路径最大值

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 110;
int dp[N][N];

void init()
{
    for (int i = 1; i <= N; i ++ )
            for (int j = 1; j <= i; j ++ )
                dp[i][j] = 0;
}

int main()
{
    int c, n;
    cin >> c;
    while (c --)
    {
        cin >> n;
        int res = 0;
        for (int i = 1; i <= n; i ++ ) //输入数组
            for (int j = 1; j <= i; j ++ )
                cin >> dp[i][j];
        //计算第一列结点最大值
        for (int i = 2; i <= n; i ++) dp[i][1] += dp[i-1][1];        
        //计算其余结点最大值
        for (int i = 2; i <= n; i ++ )
            for (int j = 2; j <= i; j ++ )
                dp[i][j] += max(dp[i-1][j],dp[i-1][j-1]);
        //找到叶子结点最大值
        for (int i = 1; i <= n; i ++)
            res = max(res,dp[n][i]);
            
        cout << res << endl;
    }

    return 0;
}

2085-核反应堆

观察规律,找到公式即可

#include <iostream>

using namespace std;

bool is_Prime(int a)
{
    if (a < 2) return false;
    for (int i = 2; i <= a/i; i++)
        if (a % i == 0) return false;
    return true;
}


int main()
{
    int n;
    while(scanf("%d",&n) != EOF)
    {
        if (n == -1) break;
        long long h_old = 1, l_old = 0;
        while(n--)
        {
            long long h_add_h = 3*h_old;
            long long h_add_l = h_old;

            long long l_add_h = 2*l_old;
            long long l_add_l = l_old;

            h_old = h_add_h + l_add_h;
            l_old = h_add_l + l_add_l;
        }
        cout << h_old << ", " << l_old << endl;
    }

    return 0;
}

2087-剪花布条

本题数据量小,可直接枚举n²,若数据量大,考虑KMP

#include <iostream>
#include <string>
#include <algorithm>

using namespace std;

string a, b;
int len1 ,len2;
bool get_num (int idx)
{
    for (int i = idx, j = 0; i < len1 && j < len2; i++, j++ )
    {
        if(a[i] != b[j]) return false;
    }
    return true;
}
int main()
{
    while (cin >> a)
    {
        int cnt = 0;
        if(a == "#") return 0;
        cin >> b;
        len1 = a.size();
        len2 = b.size();
        
        for (int i = 0; i <= len1-len2;  )
        {
            if(get_num(i)) 
            {
                cnt++;
                i += len2;
            } else i++;
        }
        cout << cnt << endl;
    }   
    return 0;
}

2089-不要62

把数字转为字符串,并判断是否符合题意

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1e6 + 10;
int f[N];

bool is_62 (int x)
{
    string s;
    char a;
    while (x) //将int x 转为 string x(倒序)
    {
        a = x % 10 + '0'; 
        s += a;
        x /= 10;
    }
    int len = s.size();
    for (int i = 0; i < len - 1; i++) 
    {
        if(s[i] == '2' && s[i+1] == '6') return true;
        if(s[i] == '4') return true;
    }
    if(s[len-1] == '4') return true;
    return false;
}

int main()
{
    int n, m, cnt = 0;
    for (int i = 1; i <= 1e6; i ++ )
        if(!is_62(i)) 
        {
            f[i] = ++cnt;
        } else f[i] = f[i-1];
    while (cin >> n >> m)
    {
        if(n == 0 && m == 0) return 0;
        int ans = f[m] - f[n-1];
        printf("%d\n",ans);
    }
    
    return 0;
}

2091-空三角形

观察位置规律,写出公式即可

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int main()
{
    char op;
    int n;
    while(cin >> op)
    {
        if(op == '@') break;
        cin >> n;
        if(n == 1) {
            cout << op << endl;
            puts("");
        }
        else {
            for(int i = 1; i < n; i++)
            {
                int k = 2*n-1;
                int mid = k / 2 + 1;
                for (int j = 1; j <= k; j++)
                {
                    if((j == mid - i + 1) || (j == mid + i - 1)) cout << op;
                    else cout << " ";
                }
                cout << endl;
            }
            for (int i = 1; i <= (2*n-1); i ++ ) cout << op;
            puts("");
        }
        puts("");
    }
    return 0;
}

2093-考试排名

结构体/输入/输出/重载比较运算

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <iomanip> 

using namespace std;

typedef struct Acm
{
    string name = "";
    int ac = 0;
    int time = 0;
} Acmer;

bool cmp (Acmer a, Acmer b)
{
    if(a.ac == b.ac) return a.time < b.time;
    else return a.ac > b.ac;
}

int main()
{
    vector<Acmer> v;
    string s;
    int n, m;
    cin >> n >> m;

    while(cin >> s)
    {
        Acmer acm;
        acm.name = s;
        int sorce, worse;
        for (int i = 1; i <= n; i ++ )
        {
            cin >> sorce;
            if (sorce <= 0) continue;
            acm.ac++;
            acm.time += sorce;
            if(getchar() == '(') 
            {
                cin >> worse;
                acm.time += worse * m;
                getchar();
            }
        }
        v.push_back(acm);
    }
    
    sort(v.begin(), v.end(), cmp);
    
    for (auto w : v) 
        cout << left  << setw(10) << w.name << " "
             << right << setw(2)  << w.ac   <<" "
             << right << setw(4)  << w.time <<endl;
    
    return 0;
}

2092-整数解

数学问题

化简得:xx - nx + m == 0 ,开口向上的抛物线,从对称轴往右侧遍历直到左式不小于0,判断其中是否有整数解

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int n, m;

bool is_int (int x) 
{
    while (x*x - n*x + m < 0)
    {
        x++;
    }
    return x * (n - x) == m;
}

int main()
{
    while (cin >> n >> m)
    {
        if(n == 0 && m == 0) return 0;
        
        if (n * n - 4 * m < 0) cout << "No" << endl;
        else {
            int mid = n / 2; //对称轴   
            if(is_int(mid)) cout << "Yes" << endl;
            else cout << "No" << endl;
        }
    }
    
    return 0;
}

2094-产生冠军

输入样例等价为一个有向图,当仅有一个结点入度为0时,产生冠军

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>
#include <string>

using namespace std;

int main()
{
    int n;
    string name1, name2;
    while(scanf("%d", &n), n)
    {
        map<string, int> v;
        while (n -- )
        {
            cin >> name1 >> name2;
            if(v.find(name1) == v.end()) v[name1] = 0;
            v[name2] ++;
        }

        int cnt = 0;
        for (auto w : v)
        {
            if(w.second == 0) cnt++;
            if(cnt > 1) break;
        }

        if(cnt == 1) cout << "Yes" << endl;
        else cout << "No" << endl;
    }

    return 0;
}

2095-find presen

map容器的应用

#include <iostream>
#include <cstring>
#include <algorithm>
#include <map>

using namespace std;

int main()
{
    int n, k;
    while (scanf("%d",&n),n)
    {
        map<int, int> fd;
        while (n -- ) {
            scanf("%d", &k);
            fd[k]++;
        }
        for (auto w : fd)
        {
            if(w.second == 1)
            {
                printf("%d\n",w.first);
                break;
            }
        }
    }
    
    return 0;
}

2097-Sky数

进制转换问题

#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>

using namespace std;

int ctoi (char c)
{
    if(c <= '9') return c - '0';
    if(c <= 'Z') return c - 'A' + 10;
    return c - 'a' + 10;
}

char itoc (int x)
{
    if(x <= 9) return '0' + x;
    return x - 10 + 'A';
}

int sum_10 (int x)
{
    int res = 0;
    while (x) res += x % 10, x /= 10;
    return res;
}

int sum_16 (string s)
{
    int res = 0;
    for (auto w : s)
    {
        if(w <= '9') res += w - '0';
        else res += w - 'A' + 10;
    }
    return res;
}

int sum_12 (string s)
{

    int res = 0;
    int len = s.size();
    for (int i = 0; i < len; i++)
    {
        char w = s[i];
        if(w <= '9') res += w - '0';
        else res += (int)w - 'A' + 10;
    }
    return res;
}
// 把十进制数n 转x进制
string toX (int num, int x)
{
    string s;
    while(num) s += itoc(num % x), num /= x;
    reverse(s.begin(), s.end());
    return s;
}

int main()
{
    int n;
    while (scanf("%d",&n),n)
    {
        int sum = sum_10(n);
        string s1, s2;
        s1 = toX(n, 16);
        s2 = toX(n, 12);
        int sum1, sum2;
        sum1 = sum_16(s1);
        sum2 = sum_12(s2);
        if(sum == sum1 && sum == sum2)
            printf("%d is a Sky Number.\n",n);
        else printf("%d is not a Sky Number.\n",n);       
    }  
    return 0;
}

2099-整数的尾除

分析规律:补上 余数与除数的差额 ,即可得到当前最小可被整除的数

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 41;
long long f[N];


int main()
{
    char c;
    int a, b;
    while (cin >> a >> b)
    {
        if (a == 0 && b == 0) break;
        a = a * 100;
        int k = a % b;
        if(k != 0)
        {
            a += b - k;
            k = a % 100;
        }
        while(k < 100)
        {
            printf("%02d ",k);
            k += b;
        }
        puts("");
    }
    
    
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

superzheng__

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值