杭电OJ 2000-2100题解

文章提供了多个C++编程题目,涉及算法和数据结构的应用,包括排序、查找、数学计算、字符串处理、图形问题等,旨在锻炼和提升读者的编程解决问题能力。
摘要由CSDN通过智能技术生成

2000题解:

#include <iostream>
#include <string>//hduoj中要用string

using namespace std;

int main()
{
    string s;
    while(cin >> s)
    {
        if(s[0] > s[1]) swap(s[0], s[1]);
        if(s[1] > s[2]) swap(s[1], s[2]);
        if(s[0] > s[1]) swap(s[0], s[1]);
        cout << s[0] << ' ' << s[1] << ' ' << s[2] << endl;
    }
    
    return 0;
}

2001题解:

#include <iostream>
#include <string>//hduoj中要用string
#include <cmath>

using namespace std;

int main()
{
   float x, y, a, b;//题目中没说是整数!
   while(cin >> x >> y >> a >> b)
   {
       double dist = sqrt((a - x) * (a - x) + (b - y) * (b - y));
       printf("%.2lf\n", dist);
   }
   return 0;
}

2002题解:

#include <iostream>
#include <string>
#include <cmath>

const double pai = 3.1415927;

using namespace std;

int main()
{
    double x;//尽量都用double类型,别用float
    while(cin >> x)
    {
        printf("%.3lf\n", 4.0 / 3 * pai * pow(x, 3));
    }
    return 0;
}

2003题解:

#include <iostream>

using namespace std;

int main()
{
    double x;
    while(scanf("%lf", &x) != EOF)
    {
        printf("%.2lf\n", abs(x));
    }
    return 0;
}

2004题解:

#include <iostream>

using namespace std;

int main()
{
    int x;
    while(scanf("%d", &x) != EOF)
    {
        if(x >= 90 && x <= 100) puts("A");
        else if(x >= 80 && x <= 89) puts("B");
        else if(x >= 70 && x <= 79) puts("C");
        else if(x >= 60 && x <= 69) puts("D");
        else if(x >= 0 && x <= 59) puts("E");
        else puts("Score is error!");
    }
    return 0;
}

2005题解:闰年的判断:四年一闰,百年不闰,四百年一闰;(闰年2月为29天)

#include <iostream>
#include <string>

using namespace std;

int mon[14];

bool check(int x)
{
    if(x % 4 == 0 && x % 100 != 0 || x % 400 == 0) return true;
    return false;
}

int main()//判断闰年
{
    for(int i = 1; i <= 12; i ++)
    {
        if(i == 1 || i == 3 || i == 5 || i == 7 || i == 8 || i == 10 || i == 12)
            mon[i] = 31;
        else mon[i] = 30;
    }
    
    int year, month, day;
    while(scanf("%d/%d/%d", &year, &month, &day) != EOF)
    {
        if(check(year)) mon[2] = 29;
        else mon[2] = 28;
        
        int res = 0;
        for(int i = 1; i < month; i ++)
        {
            res += mon[i];
        }
        res += day;
        cout << res << endl;
    }
    return 0;
}

2006题解:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    int n;
    while(cin >> n)
    {
        int res = 1;
        while(n --)
        {
            int x;
            cin >> x;
            if(x % 2 != 0) res *= x;
        }
        cout << res << endl;
    }
    return 0;
}

2007题解:

#include <iostream>
#include <string>
#include <cmath>

using namespace std;

int main()
{
    int a, b;
    while(cin >> a >> b)
    {
        if(a > b) swap(a, b);
        
        int res_one = 0, res_two = 0;
        for(int i = a; i <= b; i ++)
        {
            if(i % 2 == 0) res_one += pow(i, 2);
            else res_two += pow(i, 3);
        }
        
        cout << res_one << ' ' << res_two << endl;
    }
    return 0;
}

2008题解:

#include <iostream>
#include <string>
#include <cmath>

using namespace std;

int main()
{
    int n;
    while(cin >> n)
    {
        if(n == 0) break;
        int neg = 0,  pos = 0, zero = 0;
        while(n --)
        {
            double x;
            cin >> x;
            if(x < 0) neg ++;
            else if(x > 0) pos ++;
            else zero ++;
        }
        cout << neg << ' ' << zero << ' ' << pos << endl;
    }
    return 0;
}

2009题解:

#include <iostream>
#include <string>
#include <cmath>

using namespace std;

int main()
{
    double n, m;
    while(cin >> n >> m)
    {
        double res = n;
        m --;
        while(m --)
        {
           n = sqrt(n);
           res += n;
        }
        printf("%.2lf\n", res);
    }
    return 0;
}

2010题解:

#include <iostream>
#include <string>
#include <cmath>
#include <vector>

using namespace std;

bool check(int x)
{
    int s = x, sum = 0;
    while(s > 10)
    {
        sum += pow(s % 10, 3);
        s = s / 10;
    }
    sum += pow(s, 3);
    
    if(sum == x) return true;
    else return false;
}

int main()
{
    int m, n;
    while(cin >> m >> n)
    {
        vector<int> res;
        for(int i = m; i <= n; i ++)
            if(check(i)) res.push_back(i);
        
        if(res.size())
        {
            cout << res[0];
            for(int i = 1; i < res.size(); i ++) cout << ' ' << res[i];
            cout << endl;
        }
        else puts("no");
    }
    return 0;
}

2011题解:

#include <iostream>
#include <string>
#include <cmath>

using namespace std;

int main()//奇数正 偶数负
{
    int m;
    cin >> m;
    while(m --)
    {
        int n;
        cin >> n;
        double sum = 0;
        for(int i = 1; i <= n; i ++)
        {
            if(i % 2 == 0) sum -= 1.0 / i;
            else sum += 1.0 / i;
        }
        printf("%.2lf\n", sum);
    }
    return 0;
}

2012题解:

#include <iostream>
#include <string>
#include <cmath>

using namespace std;

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

int main()
{
    int x, y;
    while(cin >> x >> y)
    {
       if(!x && !y) break;
       
       bool success = true;
       for(int i = x; i <= y; i ++)
       {
           if(!check(i * i + i + 41)) success = false;
       }
      if(success) puts("OK");
      else puts("Sorry");
    }
    return 0;
}

2013题解:

#include <iostream>
#include <string>
#include <cmath>

using namespace std;


int main()
{
    int n;
    while(cin >> n)
    {
        int sum = 1;
        for(int i = 1; i < n; i ++)
        {
            sum = (sum + 1) * 2;
        }
        cout << sum << endl;
    }
    return 0;
}

2014题解:

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

using namespace std;


int main()
{
    int n;
    while(cin >> n)
    {
        int mi = 100, mx = 0, sum = 0;
        for(int i = 0; i < n; i ++)
        {
            int x;
            cin >> x;
            mi = min(x, mi);
            mx = max(x, mx);
            sum += x;
        }
        printf("%.2lf\n", (double)(sum - mi - mx) / (n - 2));
    }
    return 0;
}

2015题解:

#include <iostream>
#include <string>
#include <vector>

using namespace std;


int main()
{
    int n, m;
    while(cin >> n >> m)
    {
        int sum = 0;
        int x = 2;
        vector<int> res;
        for(int i = 1; i <= n; i ++)
        {
            sum += x;
            x += 2;
            if(i % m == 0)
            {
                res.push_back(sum / m);
                sum = 0;
            }
        }
        if(sum) res.push_back(sum / (n % m));
        
        cout << res[0];
        for(int i = 1; i < res.size(); i ++) cout << ' ' << res[i];
        cout << endl;
    }
    return 0;
}

2016题解:

#include <iostream>
#include <string>
#include <vector>

using namespace std;


int main()
{
    int n;
    while(cin >> n)
    {
        if(!n) break;
        
        vector<int> res;
        int mi = 0x3f;
        int j = 0;
        for(int i = 0; i < n; i ++)
        {
            int x;
            cin >> x;
            res.push_back(x);
            if(x < mi) 
            {
                mi = x;
                j = i;
            }
        }
        swap(res[0], res[j]);
        
        cout << res[0];
        for(int i = 1; i < n; i ++) cout << ' ' << res[i];
        cout << endl;
    }
    return 0;
}

2017题解:

#include <iostream>
#include <string>
#include <vector>

using namespace std;


int main()
{
    int n;
    cin >> n;
    while(n --)
    {
        string s;
        cin >> s;
        int cnt = 0;
        for(int i = 0; i < s.size(); i ++)
        {
            if(s[i] >= '0' && s[i] <= '9') cnt ++;
        }
        cout << cnt << endl;
    }
    return 0;
}

2018题解:关键是找到第n年的牛的组成关系!

已知小母牛从第四年开始会生孩子

所以第n年的牛 = 第n - 3年的牛数量(这年的所有牛在第n年都会生一个孩子) + 去年的牛数量;

用递归找前面年份的牛数量即可;

#include <iostream>
#include <string>

using namespace std;

int calc(int x)
{
    if(x == 1) return 1;
    else if(x == 2) return 2;
    else if(x == 3) return 3;
    
    else return calc(x - 1) + calc(x - 3);//公式
}

int main()
{
    int n;
    while(cin >> n)
    {
        if(n == 0) break;
        cout << calc(n) << endl;
    }
    return 0;
}

2019题解:上来直接排序复杂度高,已知有序找到相应位置插入即可;

#include <iostream>
#include <string>
#include <vector>

using namespace std;

const int N = 110;

int main()
{
    int n, m;
    while(cin >> n >> m)
    {
        if(!n && !m) break;
        
        int i = 0;
        bool s = false;
        int a[N];
        for(int i = 0; i < n; i ++) cin >> a[i];
        
        for(i; i < n; i ++)
        {
            if(a[i] < m) cout << a[i] << ' ';
            else 
            {
                if(i == n) cout << m;
                else cout << m << ' ';
                s = true;
                break;
            }
        }
        if(i == n - 1 && !s) cout << m;
        else if(i == n - 1 && s) cout << a[i];
        else
        {
            while(i != n) 
            {
                if(i == n - 1) cout << a[i];
                else cout << a[i] << ' ';
                i ++;
            }
        }
        cout << endl;
    }
    return 0;
}

2020题解:

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

using namespace std;

const int N = 110;

int main()
{
    int n;
    while(cin >> n)
    {
        unordered_map<int, int> h;
        vector<int> a;
        if(!n) break;
        for(int i = 0; i < n; i ++)
        {
            int x;
            cin >> x;
            h[abs(x)] = x;
            a.push_back(abs(x));
        }
        sort(a.rbegin(), a.rend());
        
        cout << h[a[0]];
        for(int i = 1; i < n; i ++) cout << ' ' << h[a[i]];
        cout << endl;
    }
    return 0;
}

2050题解:

首先我们要了解直线分割空间:每多增加一条直线,最多与n - 1条直线相交;每经过一个区域就会分割当前区域,则会有n 个区域被分割,又a0 = 1; a1 = 1 + 1, a2 = 1 + 1 + 2...可知 f(n) = f(n - 1) + n;

下面考虑折线情况:

其实折线可以看成有特定限制的两条直线;

在直线的基础上,每一条折线(有限制的直线)会比正常两条直线少分割两个区域(考虑折点处)

所以当有n条折线时,相当于在2n条直线所划分的区域基础上,减去 2n 个区域  

即x条折线: x = 2 * x;   (x + 1) * (x / 2) + 1 - x 

#include <iostream>

using namespace std;

int main()
{
    int n;
    cin >> n;
    while(n --)
    {
        int x;
        cin >> x;
        x = 2 * x;
        cout << (x + 1) * (x / 2) + 1 - x << endl;
    }
}

2051题解:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    int x;
    while(cin >> x)
    {
        vector<int> res;
        while(x)
        {
            res.push_back(x % 2);
            x /= 2;
        }
        for(int i = res.size() - 1; i >=0; i --) cout << res[i];
        cout << endl;
    }
    return 0;
}

2052题解:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    int n, m;
    while(cin >> n >> m)
    {
        for(int i = 0; i < m + 2; i ++)
        {
            for(int j = 0; j < n + 2; j ++)
            {
                if((i == 0 || i == m + 1) && (j == 0 || j == n + 1)) cout << '+';
                else if(i == 0 || i == m + 1) cout << '-';
                else if(j == 0 || j == n + 1) cout << '|';
                else cout << ' ';
            }
            cout << endl;
        }
        cout << endl;
    }
    return 0;
}

2053题解:

#include <iostream>
#include <vector>

using namespace std;

int change(int res)
{
    if(res) return 0;
    return 1;
}

int main()
{
    int x;
    while(cin >> x)
    {
        int res = 0;
        for(int i = 1; i <= x; i ++)
        {
            if(i == 1) res = change(res);
            else if(x % i == 0) res = change(res);
        }
        cout << res << endl;
    }
    return 0;
}

2054题解:坑很多:数字类型、数字范围等等

所以要用字符串进行读入,然后处理一下小数点后无用的0;

#include <iostream>
#include <string>

using namespace std;

string deal(string x)
{
    int len = x.length();
    if(x.find('.') != string::npos)
    {
        for(int i = len - 1; x[i] == '0'; i --)
            len --;
        x = x.substr(0, len);
        
        if(x[len - 1] == '.') x = x.substr(0, len - 1);
    }
    
    return x;
}

int main()
{
    string a, b;
    while(cin >> a >> b)
    {
        a = deal(a);
        b = deal(b);
        if(a == b) puts("YES");
        else puts("NO");
    }
    return 0;
}

2055题解:

#include <iostream>
#include <string>

using namespace std;


int main()
{
    int n;
    cin >> n;
    while(n --)
    {
        char x;
        int y;
        cin >> x >> y;
        if(x >= 'a' && x <= 'z') cout << y + -1 *(x - 'a' + 1) << endl;
        else cout << y + (x - 'A' + 1) << endl;
    }
    
}

2056题解:

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

using namespace std;


int main()
{
    double x[10], y[10];
    while(cin >> x[1] >> y[1] >> x[2] >> y[2] >> x[3] >> y[3] >> x[4] >> y[4])
    {
        
        sort(x + 1, x + 5);
        sort(y + 1, y + 5);
        printf("%.2lf\n", (x[3] - x[2]) * (y[3] - y[2]));
    }
    return 0;
}

2057题解:

解法一自己写的进制转换:第一次没有AC,想了一下因为和可能会超出int范围   改为long long类型存储;

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

typedef long long LL;

using namespace std;

int number(int x)
{
    if(x >= 'A' && x <= 'Z') return x - 'A' + 10;
    else return x - '0';
}

string get_number(int x)
{
    string res;
    if(x >= 0 && x <= 9) res =  x + '0';
    else res = 'A' + (x - 10);
    return res;
}

LL change(string x)//秦九韶算法
{
    LL res = 0;
    for(int i = 0; i < x.size(); i ++)
    {
        res = res * 16 + number(x[i]);
    }
    
    return res;
}

void calc(LL x)
{
    bool st = false;
    if(x < 0) st = true, x = abs(x);
    
    vector<LL> res;
    while(x)
    {
        res.push_back(x % 16) ;
        x /= 16;
    }
    reverse(res.begin(), res.end());
    
    if(st) cout << '-';
    
    for(auto c : res) cout << get_number(c);
    cout << endl;
}

int main()//16进制
{
    string a, b;
    while(cin >> a >> b)
    {
        LL res;
        int tag_a, tag_b;
        if(a[0] == '-') tag_a = 1, a = a.substr(1, a.size() - 1);
        else if(a[0] == '+') tag_a = 0, a = a.substr(1, a.size() - 1);
        else tag_a = 0;
        
        if(b[0] == '-') tag_b = 1, b = b.substr(1, b.size() - 1);
        else if(b[0] == '+') tag_b = 0, b = b.substr(1, b.size() - 1);
        else tag_b = 0;
        
        if(tag_a && tag_b) res = -(change(a) + change(b));
        else if(!tag_a && !tag_b) res = change(a) + change(b);
        else if(!tag_a && tag_b) res = change(a) - change(b);
        else res = change(b) - change(a);
        
        if(res == 0) cout << '0' << endl;
        else calc(res);
    }
    return 0;
}

解法二:用c++的关键字(方便)

ps:

1. hex表示之后的数字以16进制方式输出
    oct表示之后的数字以8进制方式输出
    dec表示之后的数字以10进制方式输出

2.setiosflags(ios::uppercase) 16进制数大写输出

#include <iostream>
#include <cmath>
#include <iomanip>
using namespace std;
 
int main()
{
	long long A,B;
	while(cin>>hex>>A>>B)
	{
		long long sum;
		sum=A+B;
		if(sum>=0)
			cout<<setiosflags(ios::uppercase)<<hex<<sum<<endl;
		else
		{	long long asum=abs(sum);
			cout<<"-";
			cout<<setiosflags(ios::uppercase)<<hex<<asum<<endl;
		}
	}
}

2058题解:

穷举左右端点时间复杂度太高;所以利用求和公式 只需要一次遍历

Sn = n * a1 + n ^(n - 1) / 2 * d; 所以只需要枚举区间长度 判断是否满足上述表达式即可;

//求子序列(连续)和 == M 并且输出序列;
#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

int main()
{
    int n, m;
    while(cin >> n >> m)
    {
        if(!n && !m) break;
        int maxlen = sqrt(m * 2);
        for(int i = maxlen ;i > 0; i --)
        {
            int t = m - i *(i - 1) / 2;
            if(t % i == 0) printf("[%d,%d]\n", t / i, t / i + i - 1);
        }
        
        cout << endl;
    }
}

2059题解:DP问题(多练)

DP问题:状态表示:f[i] 表示到第i个加油站的最短时间;

                状态表示方程:f[i] = 最小值:从j处加满油 到 i 点的时间 + 到 j 点的最短时间;

遍历j点 找出最优解即可;

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

const int N = 110, INF = 100000010;

double f[N], d[N];
double l, c ,t, vr, vt1, vt2;
int n;

int main()
{
    while(cin >> l >> n >> c >> t >> vr >> vt1 >> vt2)
    {
        for(int i = 1; i <= n; i ++) cin >> d[i];
        d[n + 1] = l;
        for(int i = 1; i <= n + 1; i ++)
        {
            f[i] = INF;
            for(int j = 0; j < i; j ++)
            {
                double Time;
                if(d[i] - d[j] <= c) Time = (d[i] - d[j]) / vt1;
                else Time = c / vt1 + (d[i] - d[j] - c) / vt2;
                Time += f[j];
                
                if(j > 0) Time += t;
                f[i] = min(f[i], Time);
            }
        }
        
        if(f[n + 1] < (l / vr)) puts("What a pity rabbit!");
        else puts("Good job,rabbit!");
        
    }
}

2060题解:

#include <iostream>
#include <algorithm>
#include <cmath>

using namespace std;

int n;

int main()
{
    cin >> n;
    while(n --)
    {
        int b, p, o;
        cin >> b >> p >> o;
        
        if(b > 6) p += (b - 6) * 8 + 27;
        else p += 7 * b - (b * (b - 1) / 2);
        
        if(p >= o) puts("Yes");
        else puts("No");
    }
    return 0;
}

2061题解:本身问题很简单,但是要小心数据类型;

第一次用int 型 TLE:发现数据有可能为浮点数,改为double 后AC;(没说数据类型的都用double!)

#include <iostream>
#include <string>

using namespace std;

int n;

int main()
{
    cin >> n;
    while(n --)
    {
        int k;
        double a = 0, b = 0;
        scanf("%d", &k);
        
        bool success = true;
        while(k --)
        {
            char name[35];
            double c, s;
            scanf("%s%lf%lf", name, &c, &s);
            
            if(s >= 0 && s < 60) success = false;
            else a += c * s, b += c;
        }
        
        if(!success) printf("Sorry!\n");
        else printf("%.2lf\n",a / b);

		if(n!=0) printf("\n");
    }
    return 0;
}

2062题解:

第一次WA:又是数据类型!!20个数组的集合数量为6613313319248080000 超出int型了 所以要用long long存储!

思想:一组一组的找,每找到一组,将当前数字去掉,m变为n - 1个数中的集合下标,直到找完或者m == 0为止;

#include <iostream>
#include <string>
#include <vector>

using namespace std;

typedef long long LL;

const int N = 30;

LL c[N];

int main()
{
    LL n, m;
    c[1] = 1;
    for(int i = 2; i <= N; i ++) c[i] = i * (c[i - 1] + 1);//统计i个数的集合数量
    
    while(cin >> n >> m)
    {
        vector<int> a;
        bool is_first = true;
        for(int i = 1; i <= n; i ++) a.push_back(i);
        
        while(m && n)
        {
            LL x = (m - 1) / (c[n - 1] + 1);//表示属于第几组
            if(is_first)//输出
            {
                cout << a[x];
                is_first = false;
            }
            else cout << ' ' << a[x];
            
            a.erase(a.begin() + x);//去掉该数
            m = (m - 1) % (c[n - 1] + 1);//m变为下一轮要求的第m个集合
            n --;
        }
        cout << endl;
        
    }
    return 0;
}

2063题解:

二分图匹配问题:匈牙利算法

匈牙利算法的核心是寻找増广路,是一种用增广路径求二分图最大匹配的算法。如果找不到増广路了,说明已经达到最大匹配。

总结就是两句:先到先得(匹配上了就先记录下来),能让就让(如果被别人匹配走了,看看那个女生可不可以选别人,如果可以她就让给你--find一下看看能不能找别人--此时匹配过的男生就不看了  所以每次一个女生选人时要标记一下)

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

using namespace std;

const int N = 1010;

int n, m, k;
int map[N][N];//关系
int vis[N];//是否询问过
int match[N];//男i的匹配对象;

int find(int x)
{
    for(int i = 1; i <= n; i   ++)//匹配男生
    {
        if(vis[i] == 0 && map[x][i])
        {
            vis[i] = 1;
            if(match[i] == -1 || find(match[i]))//男生未被选择(先到先得) or 被选了但是女二可以找到其他对象(让给她!)
            {
                match[i] = x;
                return 1;
            }
        }
    }
    
    return 0;
}

int main()
{
    while( cin >> k)
    {
        if(k == 0) break;
        
        cin >> m >> n;
        memset (map, 0, sizeof map);  
        memset (match, -1, sizeof match); 
        while(k --)
        {
            int a, b;
            cin >> a >> b;
            map[a][b] = 1;
        }
        
        int res = 0;
        for(int i = 1; i <= m; i ++)
        {
            memset(vis, 0, sizeof vis);//每次选择个
            if(find(i)) res ++;
        }
        cout << res << endl;
    }
    
    
    return 0;
}

2064题解:

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

using namespace std;

typedef long long LL;

int n;

LL calc(int x)
{
    if(x == 1) return 2;
    else return 3 * calc(x - 1) + 2;
}

int main()
{
    while(cin >> n)
    {
        cout << calc(n) << endl;
    }
    
    return 0;
}

2065题解:先找规律,发现是快速幂问题;

快速幂:等价替换:判断一下奇偶,然后底数一次次的算平方

#include <iostream>
#include <string>
#include <cmath>

using namespace std;

typedef long long LL;

int n;

int calc(LL x, LL m)//等价替换:判断一下奇偶,然后底数一次次的算平方
{
    int res = 1;
    while(m)
    {
        if(m % 2 == 1)//m为奇数时提出一个x最后再乘进去,最后到1时乘上res(1或者x 取决于m最初是否为奇数)
        {
            res = (res * x) % 100;
        }
        m >>= 1;//m = m / 2
        x = (x * x) % 100;//相当于指数拿出个2让底数变为平方
    }
    return res;
}

int main()
{
    while(cin >> n)
    {
        if(!n) break;
        for(int i = 1; i <= n; i ++)
        {
            LL x;
            cin >> x;
            
            int res = calc(4, x - 1) + calc(2, x - 1);
            cout << "Case "<< i << ": ";
            cout << res % 100 << endl;
        }
        cout << endl;
        
        
    }
    
    return 0;
}

2066题解:dijkstra问题

小心 a 到 b 可能有多条路径(取最小的即可)

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

using namespace std;
 
const int N = 1010; 

int n, T, S, D;
int g[N][N];
int dist[N];
bool st[N];

void dijkstra(int s)
{
    memset(dist, 0x3f, sizeof dist);
    memset(st, 0, sizeof st);
    dist[s] = 0;
    
    for(int i = 0; i < n; i ++)
    {
        int t = -1;
        for(int j = 1; j <= n; j ++)
        {
            if(!st[j] && (t == -1 || dist[j] < dist[t]))
                t = j;
        }
        st[t] = true;
        
        for(int j = 1; j <= n; j ++)
            if(dist[j] > dist[t] + g[t][j])
                dist[j] = dist[t] + g[t][j];
    }
}

int main()
{
    while(cin >> T >> S >> D)
    {
        n = 0;
        memset(g, 0x3f, sizeof g);
        
        while(T --)
        {
            int a, b, w;
            cin >> a >> b >> w;
            g[a][b] = g[b][a] = min(g[a][b], w);
            n = max(a, n);
            n = max(b, n);
        }
        
        vector<int> h_city;
        while(S --)
        {
            int x;
            cin >> x;
            h_city.push_back(x);
        }
        
        vector<int> d_city;
        while(D --)
        {
            int x;
            cin >> x;
            d_city.push_back(x);
        }
        
        int res = 100000;
        for(auto c : h_city)
        {
            dijkstra(c);
        
            for(auto item : d_city)
            {
                res = min(res, dist[item]);
            }
        }
        
        cout << res << endl;
    }
    return 0;
}

2067题解:(数学问题)卡特兰数!

1,1,2,5,14,42,132,429......


#include <cstdio>

using namespace std;

int main()
{
	long long Catalan[40] = {0};
	Catalan[0] = 1;
	Catalan[1] = 1;
	for (int i = 2 ; i <= 35 ; i++)
		for (int j = 0 ; j <= i - 1 ; j++)
			Catalan[i] += Catalan[j] * Catalan[i - 1 - j];
	int num = 1;
	int n;
	while (~scanf ("%d",&n) && n != -1)
		printf ("%d %d %lld\n",num++,n,Catalan[n] * 2);
	return 0;
}

2068题解:数学问题,找排序规律

保证一半及以上正确,找剩下的位置错排的方案

#include <iostream>

using namespace std;

const int N = 26;

int d[N];

long long C(int a, int b)
{
    long long x = 1, y = 1;
    for(int i = 1; i <= b; i ++) y *= i;
    
    for(int i = 0; i < b; i ++)
    {
        x *= a --;
    }
    int res = x / y;
    return res;
}

int main()
{
    int n;
    d[1] = 0, d[2] = 1;
        for(int i = 3; i <= 12; i ++) d[i] = (i - 1) * (d[i - 1] + d[i - 2]);
    while(cin >> n)
    {
        if(!n) break;
        long long cnt = 1;
        for(int i = 1; i <= n / 2; i ++)//遍历错排的个数求总和
        {
            cnt += C(n, i) * d[i];//选择的人数 * 错排的方案数
        }
        cout << cnt << endl;
    }
}

2069题解:

有限制的完全背包问题;

没限制硬币个数的话很简单,就是单纯的完全背包问题;

但是限制硬币个数 <= 100;一开始想用双状态表示,

f[i][j]表示使用前i种硬币(5种)下总和为j的方案数,但是要记录每个方案使用的硬币个数非常复杂。不可取

则考虑换一种状态表示:计算使用前i个硬币(100个)下总和达到j的方案数量;

最后从1 - 100遍历求总的方案数即可;

//完全背包问题
#include <iostream>
#include <cstring>
#include <string>

using namespace std;

const int N = 260;

long long f[N][N];//用100个硬币下总和为j的方案
int w[6] = {0, 1, 5, 10, 25, 50};
int s[N][N];//记录总硬币个数
int main()
{
    int n;
    
    memset(f, 0, sizeof f);
    f[0][0] = 1;
        
    for(int i = 1; i <= 5; i ++)//对每个物品用100次,求方案
        for(int j = 1; j <= 100; j ++)
            for(int k = w[i]; k <= 251; k ++)
                f[j][k] += f[j - 1][k - w[i]];
                
    while(cin >> n)
    {
        long long res = 0;
        for(int i = 0; i <= 100; i ++) res += f[i][n];
        
        cout << res << endl;
    }
    
    return 0;
}

2070题解:

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

using namespace std;

const int N = 51;

long long a[N];

int main()
{
    int n;
    a[0] = 0, a[1] = 1;
    for(int i = 2; i <= N; i ++) a[i] = a[i - 1] + a[i - 2];
    while(cin >> n)
    {
        if(n == -1) break;
        cout << a[n] << endl;
    }
    
    return 0;
}

2071题解:

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

using namespace std;

const int N = 51;

long long a[N];

int main()
{
    int n;
    cin >> n;
    while(n --)
    {
        int k;
        cin >> k;
        double mx = 0;
        while(k --)
        {
            double x;
            cin >> x;
            mx = max(x, mx);
        }
        printf("%.2lf\n", mx);
    }
    
    return 0;
}

2072题解:

用stringstream进行二次读入⭐ 头文件<sstream>

map记录出现过的单词

#include <iostream>
#include <string>
#include <sstream>
#include <unordered_map>

using namespace std;

int main()
{
    string line;
    while(getline(cin, line))
    {
        if(line == "#") break;
        
        unordered_map<string, int> words;
        
        stringstream sinn(line);
        string word;
        while(sinn >> word)
        {
            words[word] ++;
        }
        
        cout << words.size() << endl;
    }
    
    return 0;
}

2073题解:

前缀和思想:两点求差  == 各自到原点的距离之差;

到原点:找有规律的点存储下来,在基础上进行计算

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

using namespace std;

const int N = 200;

double d[N];

double find(int a, int b)
{
    double res;
    res = d[a + b] - b * sqrt(2);
    return res;
}

int main()
{
    int n;
    cin >> n;
    d[1] = 1 + sqrt(2);
    for(int i = 2; i <= N; i ++) d[i] = d[i - 1] + i * sqrt(2) + sqrt((i - 1) * (i - 1) + i * i);
    
    while(n --)
    {
        int x1, x2, y1, y2;
        cin >> x1 >> y1 >> x2 >> y2;
        
        double res = abs(find(x1, y1) - find(x2, y2));
        
        printf("%.3lf\n", res);
    }
    
    return 0;
}

2074题解:

要特判一个字符的时候

并且注意之间的空行

#include <iostream>
#include <string>

using namespace std;


int main()
{
    int n, count = 0;
    char a, b;
    
    while(cin >> n >> a >> b)
    {
        
        if(count != 0) printf("\n"); //踩坑点2 
        
		count = 1;
        
        if(n == 1) 
        {
            printf("%c\n", a);
            continue;
        }
        
        string f[81][81];
        if(n / 2 % 2 == 0) swap(a, b);
        int m = n;
        for(int i = 0, j = 0; i < n / 2 || j < n / 2; i ++, j ++)
        {
            for(int k = j; k < m; k ++) f[i][k] = b;
            
            for(int k = i; k < m; k ++) f[k][j] = b;
            swap(a, b);
            m --;
        }
        
        m = 0;
        if(n / 2 % 2 == 0) swap(a, b);
        for(int i = n - 1, j = n - 1; i > 0 || j > 0; i --, j --)
        {
            for(int k = j; k >= m; k --) f[i][k] = a;
            
            for(int k = i; k >= m; k --) f[k][j] = a;
            swap(a, b);
            m ++;
        }
        
        f[0][0] = " ", f[0][n - 1] = " ", f[n - 1][0] = " ", f[n - 1][n - 1] = " ";

        
        for(int i = 0; i < n; i ++)
        {
            for(int j = 0; j < n; j ++)
            {
                cout << f[i][j];
            }
            cout << endl;
        }
    }
    return 0;
}

2075题解:

#include <iostream>
#include <cstdio>

using namespace std;

int main()
{
    int n;
    cin >> n;
    while(n --)
    {
        int a, b;
        cin >> a >> b;
        if(a % b == 0) puts("YES");
        else puts("NO");
    }
    
    return 0;
}

2076题解:

#include <iostream>

using namespace std;

int main()
{
    int n;
    cin >> n;
    while(n --)//求各自度数之差
    {
        double h, m, s;
        cin >> h >> m >> s;
        if(h > 12) h -= 12;
        double m_d = 6 * m+ 0.1 * s;
        double h_d = 30 * h + 0.5 * (m + s / 60);
        
        if(h_d < m_d) swap(h_d, m_d);
        
        if((h_d - m_d) > 180)
        {
            int res = 360 - h_d + m_d;
            cout << res << endl;
        }
        else
        {
            int res = h_d - m_d;
            cout << res << endl;
        }
    }
    
    return 0;
}

2077题解:

#include <iostream>

using namespace std;

int han(int x)
{
    if(x == 1) return 1;
    else return 3 * han(x - 1) + 1;
}

int main()
{
    int n;
    cin >> n;
    while(n --)//求各自度数之差
    {
        int x;
        cin >> x;
        int res;
        if(x == 1) res = 2;
        else res = 2 * han(x - 1) + 2;
        cout << res << endl;
    }
    
    return 0;
}

2078题解:

#include <iostream>
#include <algorithm>

using namespace std;

const int N = 50;

int main()
{
    int T;
    cin >> T;
    while(T --)
    {
        int n, m;
        cin >> n >> m;
        int w[N];
        int mi = 110;
        for(int i = 0; i < n; i ++)
        {
            int x;
            cin >> x;
            mi = min(x, mi);
        }
        cout << (100 - mi) * (100 - mi) << endl;
    }
    
    return 0;
}

2079题解:

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

using namespace std;

const int N = 50;
int f[9][N];
int w[N], cnt[N];
int main()
{
    int T;
    cin >> T;
    while(T --)
    {
        
        memset(f, 0, sizeof f);
        int n, k;
        cin >> n >> k;
        for(int i = 1; i <= k; i ++)
        {
            cin >> w[i] >> cnt[i];
        }
        
        f[0][0] = 1;
        
        for(int i = 1; i <= k; i ++)
            for(int j = 0; j <= n; j ++)
                for(int s = 0; s * w[i] <= j && s <= cnt[i]; s ++)
                    f[i][j] += f[i - 1][j - s * w[i]]; 
       
       cout << f[k][n] << endl;
    }
    
    return 0;
}

2080题解:

数量积公式求cos再用acos转化为角度

acos():返回弧度数(参数-1 到 1)的反余弦值,

#include <iostream>
#include <cmath>
#include <cstdio>
#include <string>
#define PI acos(-1.0)//求180°的弧长 = 3.1415926535

using namespace std;

int main()
{
	int T;
	cin >> T;
	while(T --)
	{
	    
	    double x1, y1, x2, y2;
	    cin >> x1 >> y1 >> x2 >> y2;
        //输出结果为弧度,弧度转化为角度 弧长 / PI * 180;
	    printf("%.2lf\n", acos((x1 * x2 + y1 * y2) / (sqrt(x1 * x1 + y1 *y1) * sqrt(x2 * x2 + y2 * y2))) * 180 / PI);
	}
	
	return 0;
}

2081题解:

#include <iostream>
#include <cstdio>
#include <string>

using namespace std;

int main()
{
	int T;
	cin >> T;
	while(T --)
	{
	    string s, res;
	    cin >> s;
	    for(int i = s.size() - 1; i > s.size() - 6; i --)
	    {
	        res = s[i] + res;
	    }
	    
	    cout <<'6' << res << endl;
	}
	
	return 0;
}

2082题解:

完全背包问题:求<=50的方案数

状态表示:考虑前i个数价值达到50的方案数;

则答案 = 考虑前i个数 价值从 1 - 50的方案数总和。

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

using namespace std;

const int N = 27, M = 51;

int cnt[N], f[N][M];

int main()
{
	int T;
	cin >> T;
	while(T --)
	{
	    for(int i = 1; i < N ; i ++) cin >> cnt[i];
	    memset(f, 0, sizeof f);
	    
	    f[0][0] = 1;
	    for(int i = 1; i < N; i ++)
	        for(int j = 0; j <= 50; j ++)
	            for(int k = 0; k <= cnt[i] && k * i <= j; k ++)
	            {
	                f[i][j] += f[i - 1][j - k * i];
	            }
	   
	   int res = 0;
        for(int j = 1; j <= 50; j ++) res += f[26][j];
	        
	   cout << res << endl;
	}
	
	
	
	return 0;
}

一维数组优化版本:

我们只需要考虑上一轮决策的状态,可以用一维数组从大到小更新(用到的状态体积一定是小于等于当前体积 j 的)要注意特判一下:不选当前单词时方案数应该直接等于上一个状态的方案数(想了很久才发现这个点)

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

using namespace std;

const int N = 27, M = 51;

int f[M];

int main()
{
	int T;
	cin >> T;
	while(T --)
	{
	    memset(f, 0, sizeof f);
	    f[0] = 1;
	    for(int i = 1; i < N; i ++)
	    {
	        int cnt;
	        cin >> cnt;
	        for(int j = 50; j >= 1; j --)
	            for(int k = 0; k <= cnt && k * i <= j; k ++)
	            {
	                if(k != 0) f[j] += f[j - k * i];//要考虑不选当前单词的时候,此时方案数不是相加而是相等;
	            }
	    }
	        
	   int res = 0;
       for(int j = 1; j <= 50; j ++) res += f[j];
	        
	   cout << res << endl;
	}
	
	
	
	return 0;
}

2083题解:(未跑)

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

using namespace std;

const int N = 510;

int d[N];

int main()
{
	int T;
	cin >> T;
	while(T --)
	{
	    int n;
	    cin >> n;
	    for(int i = 0; i < n; i ++) cin >> d[i];
	    sort(d, d + n);
	    int start = d[n / 2];
	    
	    int res = 0;
	    for(int i = 0; i < n; i ++) res += abs(d[i] - start);
	    
	    cout << res << endl;
	}
	return 0;
}

2084题解:

一、dfs解法:超时(意料之中)

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

using namespace std;

const int N = 110;

int res;
vector<int> h[N];

void dfs(int x, int sum, int end, int pre)
{
    if(x == end) 
       res = max(res, sum); 
    else
    {
        for(int i = pre; i <= pre + 1; i ++) 
            dfs(x + 1, sum + h[x][i], end, i);
    }
}

int main()
{
	int T;
	cin >> T;
	while(T --)
	{
	    for(int i = 0; i < N; i ++) h[i].clear();
	    
	    int n;
	    cin >> n;
	    for(int i = 1; i <= n; i ++)
	    {
	        int j = i;
	        while(j --) 
	        {
	            int x;
	            cin >> x;
	            h[i].push_back(x);
	        }
	    }
	    
	    res = 0;
	    dfs(1, 0, n + 1, 0);
	    cout << res << endl;
	}
	return 0;
}

二、DP解法

状态表示:从顶层到前i层第j个数的最大权值和;(每一层的最大值都是基于上一层每个点最大值进行决策(且最多就两种选择));

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

using namespace std;

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

int main()
{
	int T;
	cin >> T;
	while(T --)
	{
	    int n;
	    cin >> n;//层数
	    for(int i = 1; i <= n; i ++)
	        for(int j = 0; j < i; j ++) 
	        {
	            int x;
	            cin >> x;
	            if(j == 0) dp[i][j] = dp[i - 1][j] + x;
	            else if(j == i - 1) dp[i][j] = dp[i - 1][j - 1] + x;
	            else dp[i][j] = max(dp[i - 1][j - 1] + x, dp[i - 1][j] + x);
	        }
	    int res = 0;
        for(int i = 0; i < n; i ++) res = max(res, dp[n][i]);
        cout << res << endl;
	}
	return 0;
}

2085题解:简单递归问题

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

using namespace std;


void calc(int n, long long h, long long l)
{
    if(!n) cout << h << ", " << l << endl;
    else
    {
        calc(n - 1,h * 3 + l * 2, h + l);
    }
}

int main()
{
    int n;
	while(cin >> n)
	{
	    if(n == -1) break;
	    calc(n, 1, 0);
	}
	return 0;
}

2086题解:数学问题、找规律

A(n+1) = (n + 1)A1 - n * A0 + 2 * i C[n - i];(c从0 开始)

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

using namespace std;

const int N = 3010;

double c[N];

int main()
{
    int n;
	while(cin >> n)
	{
	    double a, an1;
	    cin >> a >> an1;
	    for(int i = 0; i < n; i ++) cin >> c[i];
	    
	    double a1 = an1 + n * a;
	    
	    for(int i = 1; i <= n; i ++) a1 -= 2 * i * c[n - i];
	    
	    printf("%.2lf\n", a1 / (n + 1));
	}
	return 0;
}

2087题解:字符串匹配问题;(水)

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

using namespace std;

const int N = 3010;

double c[N];

int main()
{
    string s, d;
	while(cin >> s)
	{
	    if(s == "#") break;
	    else
	    {
    	    cin >> d;
    	    
    	    int len = d.size();
    	    int cnt = 0;
    	    for(int i = 0; i < s.size(); i ++)
    	    {
    	        string z = s.substr(i, len);
    	        if(z == d) 
    	        {
    	            cnt ++;
    	            i += len - 1;
    	        }
    	    }
    	    cout << cnt << endl;
	    }
	}
	
	return 0;
}

2088题解:

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

using namespace std;

const int N = 51;

int a[N];
bool is_first = true;

int main()
{
    int n;
	while(cin >> n)
	{
	    if(!n) break;
	    else
	    {
	        if(!is_first)  cout << endl;
	        
	        is_first = false;
	        
	        int sum = 0;
	        for(int i = 0; i < n; i ++) 
	        {
	            cin >> a[i];
	            sum += a[i];
	        }
	        
	        int d = sum / n, res = 0;
	        for(int i = 0; i < n; i ++) res += max(0, a[i] - d);
	        
	        cout << res << endl;
	    }
	}
	
	return 0;
}

2089题解:一次找完10^6次方,用字符串匹配来找(strstr函数,但是注意参数为char型)

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

using namespace std;

const int N = 1e6 + 10;

int r[N];

int main()
{
    for(int i = 1; i <= N; i ++)
    {
        string cc = to_string(i);
        char s[10];
        for(int i = 0; i < cc.size(); i ++) s[i] = cc[i];
        
        if(strstr(s, "4") != NULL || strstr(s, "62") != NULL) r[i] = 0;
        else r[i] = 1;
    }
    
    int a, b;
	while(cin >> a >> b)
	{
	    if(!a && !b) break;
	    else
	    {
	        int sum = 0;
	        for(int i = a; i <= b; i ++)
	        {
	            sum += r[i];
	        }
	        cout << sum << endl;
	    }
	}
	
	return 0;
}

2090题解:(水题)

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

using namespace std;

const int N = 1e6 + 10;

int r[N];

int main()
{
    string s;
    double cnt, price, sum = 0;
	while(cin >> s >> cnt >> price)
	{
	    sum += cnt * price;
	}
	
	printf("%.1lf\n", sum);
	return 0;
}

2091题解:

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

using namespace std;

int main()
{
    string s;
    int n;
    bool is_first = true;
	while(cin >> s)
	{
	    if(s == "@") break;
	    else 
	    {
	        if(!is_first) cout << endl;
	        
	        is_first = false;
	        
	        cin >> n;
	        
	        for(int i = 0; i < n; i ++)
	        {
    	        for(int j = 0; j <= n - 1 + i; j ++)
    	        {
    	            if(i + 1 == n) cout << s;
    	            else
    	            {
    	                if(j == n - 1 - i || j == n - 1 + i) cout << s;
    	                else cout << " ";
    	            }
    	        }
    	        cout << endl;
	        }
	    }
	    
	}
	return 0;
}

2093题解:排序题 + 对输出的处理

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

using namespace std;

struct Info{
    string name;
    int ac, ti;
    
    bool operator< (const Info &t) const{
        if(ac != t.ac) return ac > t.ac;
        else if(ti != t.ti) return ti < t.ti;
        else return name < t.name;
    }
};

vector<Info> students;

int main()
{
    int n, m;
    cin >> n >> m;
    int ac_si = 0, ti_si = 0;
    string name;
    
	while(cin >> name)
	{
	    int ac = 0, ti = 0;
	    for(int i = 0;i < n; i ++)
	    {
	        string x;
	        cin >> x;
	        if(x[0] != '-' && x[0] != '0')
	        {
	            ac ++;
	            int d = x.find('(');
	            ti += stoi(x);
	            if(d != -1) ti += stoi(x.substr(d + 1, x.size() - d - 2)) * m;
	        }
	    }
	    ac_si = max(ac, ac_si);
	    ti_si = max(ti, ti_si);
	    students.push_back({name, ac, ti});
	}
	
	sort(students.begin(), students.end());
	
	for(auto c : students)
	{
	   int i = 10 - c.name.size();
	   cout << c.name;
	   while(i --) cout << ' ';
	   
	   i = 2 - to_string(c.ac).size() + 1;
	   while(i --) cout << ' ';
	   cout << c.ac;
	   
	   i = 4 - to_string(c.ti).size() + 1;
	   while(i --) cout << ' ';
	   cout << c.ti;
	   cout << endl;
	}
	
	return 0;
}

2094题解:

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

using namespace std;

int main()
{
	int n, i, j;
	string win[999], lose[999], temp;
	bool mark[999];
	while (scanf("%d", &n)) {
		if (!n) {
			break;
		}
		// 初始化标记数组
		memset(mark, 1, sizeof(mark));
		for (i = 0; i < n; i++) {
			cin >> win[i] >> lose[i];
		}
		// 标记处“无效比赛”
		for (i = 0; i < n; i++) {//j输过则它的比赛无效
			for (j = 0; j < n; j++) {
				if (win[j] == lose[i] && mark[j]) {
					mark[j] = false;
				}
			}
		}
		// 找出第一个“有效比赛”中的赢者
		for (i = 0; !mark[i]; i++) { }
		temp = win[i];
		// 判断是否所有的赢者都是一个人
		for (j = i + 1; j < n; j++) {
			if (mark[j] && win[j] != temp) {
				break;
			}
		}
		if (j != n) {
			printf("No\n");
		}
		else {
			printf("Yes\n");
		}
	}
	return 0;
}

  • 6
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值