程序設計思維與實踐 Week2 實驗 (3/4/數據班)

A - 化學 (編譯器選 GNU G++) Gym - 270437A

題意

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-ouSONz88-1583071462858)(https://espresso.codeforces.com/40fbd94c6282f47ed4c3040ecd1b29b610a0a032.png)]

假設如上圖,這個烷烴基有6個原子和5個化學鍵,6個原子分別標號1~6,然後用一對數字 a,b 表示原子a和原子b間有一個化學鍵。這樣通過5行a,b可以描述一個烷烴基

你的任務是甄別烷烴基的類別。

思路

這個題就很有意思了,我們可以分類判斷。我們可以把每一個原子看成點,其中第1個和第6個有明顯的特徵,即只有第一個最大出度爲2,最後一個最大出度爲4。同時我們可以對於每一個烷烴基找到出度最大的點。

這時以出度最大的點爲根開始dfs找最大深度,只有第2個最大深度爲3。

此時只有3,4沒有區分了,只需要刨除出度最大的點再找一個出度次大的點即可。次大出度爲2即爲第三個,爲3即爲第3個。

總結

本題情況僅爲6個,做法很多。比如還可以找最長鏈。由於爲rank,沒有仔細考慮,上述思路還有可以提升的地方,將2,3,4選擇轉化爲判斷最長鏈會更簡單。

代碼

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#define LL long long
using namespace std;
inline int get_num() {
    char c;
    int f = 1, num = 0;
    while ((c = getchar()) == ' ' || c == '\n' || c == '\r')
        ;
    if (c == '-')
        f = -1;
    else
        num = c - '0';
    while (isdigit(c = getchar())) num = num * 10 + c - '0';
    return num * f;
}
int v[10][10], vis[10], deep;
void dfs(int x, int len) {
    deep = max(len, deep);
    vis[x] = 1;
    for (int i = 1; i <= 6; i++) {
        if (v[x][i]) {
            if (!vis[i]) dfs(i, len + 1);
        }
    }
    vis[x] = 0;
}
void bfs() {
    int max_sum = 0, k = 0;
    for (int i = 1; i <= 6; i++) {
        int sum = 0;
        for (int j = 1; j <= 6; j++) {
            if (v[i][j]) {
                sum++;
            }
        }
        if (sum > max_sum) {
            max_sum = sum;
            k = i;
        }
    }
    //    cout <<"sum:" <<max_sum<<endl;
    if (max_sum == 2) {
        cout << "n-hexane" << endl;
        return;
    } else if (max_sum == 4) {
        cout << "2,2-dimethylbutane" << endl;
        return;
    }
    memset(vis, 0, sizeof(vis));
    deep = 0;
    dfs(k, 0);
    if (deep == 3) {
        cout << "2-methylpentane" << endl;
        return;
    }
    max_sum = 0;
    for (int i = 1; i <= 6; i++) {
        int sum = 0;
        if (i == k) continue;
        for (int j = 1; j <= 6; j++) {
            if (v[i][j]) {
                sum++;
            }
        }
        if (sum > max_sum) {
            max_sum = sum;
        }
    }
    if (max_sum == 3) {
        cout << "2,3-dimethylbutane" << endl;
        return;
    } else {
        cout << "3-methylpentane" << endl;
        return;
    }
}

int main() {
    int T;
    T = get_num();
    while (T) {
        T--;
        memset(v, 0, sizeof(v));
        for (int i = 1; i <= 5; i++) {
            int a, b;
            a = get_num();
            b = get_num();
            v[a][b] = v[b][a] = 1;
        }
        bfs();
    }
    return 0;
}

B - 爆零(×)大力出奇跡(√)] HDU - 2093

題意

輸入數據包含多行,第一行是共有的題數n(1≤n≤12)以及單位罰時m(10≤m≤20),之後的每行數據描述一個學生的信息,首先是學生的用戶名(不多於10個字符的字串)其次是所有n道題的得分現狀,根據這些學生的得分現狀,輸出一個實時排名。實時排名顯然先按AC題數的多少排,多的在前,再按時間分的多少排,少的在前,如果湊巧前兩者都相等,則按名字的字典序排,小的在前。每個學生佔一行,輸出名字(10個字符寬),做出的題數(2個字符寬,右對齊)和時間分(4個字符寬,右對齊)。名字、題數和時間分相互之間有一個空格。數據保證可按要求的輸出格式進行輸出。

Sample Input

8 20
GuGuDong  96     -3    40(3) 0    0    1      -8    0
hrz       107    67    -3    0    0    82     0     0
TT        120(3) 30    10(1) -3   0    47     21(2) -2
OMRailgun 0      -99   -8    0    -666 -10086 0     -9999996
yjq       -2     37(2) 13    -1   0    113(2) 79(1) -1
Zjm       0      0     57(5) 0    0    99(3)  -7    0

Sample Output

TT          5  348
yjq         4  342
GuGuDong    3  197
hrz         3  256
Zjm         2  316
OMRailgun   0    0

思路

這題核心是如何處理讀入數據,即如何區分讀入爲純數字,如:4;和讀入爲字符串,如:4(3)的情況。

只需要將每個讀入存入一個字符串,判斷字符串內是否爲純數值:

bool isNumber(const string& str) {
	istringstream in(str);
	double test;
	return in >> test && in.eof();
}

如果是純數值,負數按0處理,正數加權即可。

如果不爲純數值。只需要讀入一個數字,一個字符,一個數字,一個字符即可:

	istringstream in(s);
	LL a, b;
	char c;
	in >> a >> c >> b >> c;

結構體處理:

struct re {
    string name;
    int num;
    LL sum;
    bool operator<(const re& a) const {
        return num != a.num ? (num > a.num) : (sum != a.sum ? sum < a.sum : name < a.name);
    }
};

總結

此類問題重點在於數據的處理,重要的是模塊化,這樣解題纔會更快。

這裏實驗課的時候,忘記去除測試if(cnt == 6)(六條數據),吃了兩發WA,其實win下測試可以ctrl+zEnter就會成爲EOF了,着實被自己坑了。

代碼

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <vector>
#define LL long long
using namespace std;
inline int get_num() {
    char c;
    int f = 1, num = 0;
    while ((c = getchar()) == ' ' || c == '\n' || c == '\r')
        ;
    if (c == '-')
        f = -1;
    else
        num = c - '0';
    while (isdigit(c = getchar())) num = num * 10 + c - '0';
    return num * f;
}
bool isNumber(const string& str) {
	istringstream in(str);
	double test;
	return in >> test && in.eof();
}
LL strInt(const string& str){
	istringstream in(str);
	LL test;
	in>>test;
	return test;
}
struct re {
    string name;
    int num;
    LL sum;
    bool operator<(const re& a) const {
        return num != a.num ? (num > a.num) : (sum != a.sum ? sum < a.sum : name < a.name);
    }
} v[20];

int main() {
//	freopen("in.txt","r",stdin);
//	freopen("out.txt","w",stdout);
    int n, m;
    cin >> n >> m;
    string s;
    int cnt = 0;
    while (cin >> s) {
        v[++cnt].name = s;
//        cout << "cnt: "<<v[cnt].name<<endl;
        for (int i = 1; i <= n; i++) {
            string s;
            cin >> s;
            if (isNumber(s)) {
            	LL a = strInt(s);
                if (a <= 0) {
                } else {
                    v[cnt].sum += a;
                    v[cnt].num ++;
                }
            } else {
                istringstream in(s);
                LL a, b;
                char c;
                in >> a >> c >> b >> c;
                v[cnt].num++;
                v[cnt].sum += a + b * m;
            }
        }
//        if (cnt == 6) break;
    }
//    cout << "yes"<<endl;
//    printf("yess\n");
    sort(v + 1, v + 1 + cnt);
    for (int i = 1; i <= cnt; i++) {
        printf("%-10s ", v[i].name.c_str());
        printf("%2d ", v[i].num);
        printf("%4lld\n", v[i].sum);
    }
    return 0;
}

C - 瑞神打牌 POJ - 1786

牌局由四個人構成,圍成一圈。我們稱四個方向爲北 東 南 西。對應的英文是North,East,South,West。遊戲一共由一副撲克,也就是52張構成。開始,我們指定一位發牌員(東南西北中的一個,用英文首字母標識)開始發牌,發牌順序爲順時針,發牌員第一個不發自己,而是發他的下一個人(順時針的下一個人)。這樣,每個人都會拿到13張牌。
現在我們定義牌的順序,首先,花色是(梅花)<(方片)<(黑桃)<(紅桃),(輸入時,我們用C,D,S,H分別表示梅花,方片,黑桃,紅桃,即其單詞首字母)。對於牌面的值,我們規定2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < T < J < Q < K < A。
現在你作爲上帝,你要從小到大排序每個人手中的牌,並按照給定格式輸出。

Sample Output

South player:
+---+---+---+---+---+---+---+---+---+---+---+---+---+
|6 6|A A|6 6|J J|5 5|6 6|7 7|9 9|4 4|5 5|7 7|9 9|T T|
| C | C | D | D | S | S | S | S | H | H | H | H | H |
|6 6|A A|6 6|J J|5 5|6 6|7 7|9 9|4 4|5 5|7 7|9 9|T T|
+---+---+---+---+---+---+---+---+---+---+---+---+---+
West player:
+---+---+---+---+---+---+---+---+---+---+---+---+---+
|2 2|5 5|9 9|K K|5 5|7 7|9 9|4 4|T T|J J|A A|8 8|A A|
| C | C | C | C | D | D | D | S | S | S | S | H | H |
|2 2|5 5|9 9|K K|5 5|7 7|9 9|4 4|T T|J J|A A|8 8|A A|
+---+---+---+---+---+---+---+---+---+---+---+---+---+
North player:
+---+---+---+---+---+---+---+---+---+---+---+---+---+
|3 3|4 4|J J|2 2|3 3|T T|Q Q|K K|8 8|Q Q|K K|2 2|3 3|
| C | C | C | D | D | D | D | D | S | S | S | H | H |
|3 3|4 4|J J|2 2|3 3|T T|Q Q|K K|8 8|Q Q|K K|2 2|3 3|
+---+---+---+---+---+---+---+---+---+---+---+---+---+
East player:
+---+---+---+---+---+---+---+---+---+---+---+---+---+
|7 7|8 8|T T|Q Q|4 4|8 8|A A|2 2|3 3|6 6|J J|Q Q|K K|
| C | C | C | C | D | D | D | S | S | H | H | H | H |
|7 7|8 8|T T|Q Q|4 4|8 8|A A|2 2|3 3|6 6|J J|Q Q|K K|
+---+---+---+---+---+---+---+---+---+---+---+---+---+

思路

對於牌面的大小,開一個map來映射對應大小。一個字符串一個數值的讀入即可。由於不支持C++11,需要手動初始化map(太坑了)。

讀入完sort一下就星,可以說是這次rank的最簡單的一道題

struct re {
    char s, v;
    bool operator<(const re& a) const {
        return CARD_S[s] != CARD_S[a.s] ? CARD_S[s] < CARD_S[a.s] : CARD_V[v] < CARD_V[a.v];
    }
};

總結

沒看到題目要求,吃了三發PE。

輸出多組數據發牌的結果,每組數據之後需要額外多輸出一個空行!!!!!

一定一定要仔細仔細讀題。

代碼

#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <fstream>
#include <functional>
#include <iostream>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#define LL long long
using namespace std;
inline int get_num() {
    char c;
    int f = 1, num = 0;
    while ((c = getchar()) == ' ' || c == '\n' || c == '\r')
        ;
    if (c == '-')
        f = -1;
    else
        num = c - '0';
    while (isdigit(c = getchar())) num = num * 10 + c - '0';
    return num * f;
}
map<char, int> POS, CARD_S, CARD_V;
void dfs() {
    CARD_V['2'] = 2;
    CARD_V['3'] = 3;
    CARD_V['4'] = 4;
    CARD_V['5'] = 5;
    CARD_V['6'] = 6;
    CARD_V['7'] = 7;
    CARD_V['8'] = 8;
    CARD_V['9'] = 9;
    CARD_V['T'] = 10;
    CARD_V['J'] = 11;
    CARD_V['Q'] = 12;
    CARD_V['K'] = 13;
    CARD_V['A'] = 14;
    CARD_S['C'] = 1;
    CARD_S['D'] = 2;
    CARD_S['S'] = 3;
    CARD_S['H'] = 4;
    POS['S'] = 1;
    POS['W'] = 2;
    POS['N'] = 3;
    POS['3'] = 4;
}
struct re {
    char s, v;
    bool operator<(const re& a) const {
        return CARD_S[s] != CARD_S[a.s] ? CARD_S[s] < CARD_S[a.s] : CARD_V[v] < CARD_V[a.v];
        //        return CARD_V[v] != CARD_V[a.v] ? CARD_V[v] < CARD_V[a.v] : CARD_S[s] < CARD_S[a.s];
    }
};
struct ac {
    string s;
    vector<re> card;
} v[5];

int main() {
//     freopen("out.txt", "w", stdout);
    dfs();
    char c;
    while (cin >> c) {
        if (c == '#') break;
        
        for (int i = 1; i <= 4; i++) {
            v[i].card.clear();
        }
        int k = POS[c];
        for (int i = 1; i <= 52; i++) {
            k = (k + 1) % 4;
            if (k == 0) k = 4;
            char a, b;
            cin >> a >> b;
            re node;
            node.s = a;
            node.v = b;
            v[k].card.push_back(node);
        }
        v[1].s = "South player";
        v[2].s = "West player";
        v[3].s = "North player";
        v[4].s = "East player";
        for (int i = 1; i <= 4; i++) {
            sort(v[i].card.begin(), v[i].card.end());
            cout << v[i].s << ":\n";
            cout << "+---+---+---+---+---+---+---+---+---+---+---+---+---+" << endl;
            for (int j = 0; j < 13; j++) {
                cout << "|" << v[i].card[j].v << " " << v[i].card[j].v;
            }
            cout << "|" << endl;
            for (int j = 0; j < 13; j++) {
                cout << "| " << v[i].card[j].s << " ";
            }
            cout << "|" << endl;
            for (int j = 0; j < 13; j++) {
                cout << "|" << v[i].card[j].v << " " << v[i].card[j].v;
            }
            cout << "|" << endl;
            cout << "+---+---+---+---+---+---+---+---+---+---+---+---+---+" << endl;
        }
        cout <<endl;
    }

    return 0;
}

寫在最後

這次rank的教訓是,兩次WA是因爲自己第二題沒去掉調試信息,三次PE是因爲第三題沒看到每組數據之間要多一行空格。
最終rank 4,較上週有進步,希望下次能拿到某個題目的首A。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章