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+z
再Enter
就會成爲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。