另把天梯賽所有題解內容全部打包成了一個文檔,可以自行下載:https://download.csdn.net/download/daixinliangwyx/11170075
L2-001 城市間緊急救援
解法:裸迪傑斯特拉最短路徑+打印路徑
代碼:
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
int n, m, s, d, u, v, len;
int to[510], dis[510][510], val[510], sumpath[510], path[510], sum[510], vis[510], pre[510];
void Dijstr() {
to[s] = 0;
for(int i = 0; i < n; i++) {
int minn = inf, next = -1;
for(int j = 0; j < n; j++) {
if(vis[j] == 0 && to[j] < minn) {
minn = to[j];
next = j;
}
}
if(next == -1) break;
else
vis[next] = 1;
for(int j = 0; j < n; j++) {
if(vis[j] == 0 && to[next] + dis[next][j] < to[j]) {
to[j] = to[next] + dis[next][j];
sumpath[j] = sumpath[next];//中間點是next
sum[j] = sum[next] + val[j];
pre[j] = next;
} else if(vis[j] == 0 && to[next] + dis[next][j] == to[j]) {
sumpath[j]= sumpath[j] + sumpath[next];
if(sum[j] < sum[next] + val[j]) {
sum[j] = sum[next] + val[j];
pre[j] = next;
}
}
}
}
}
int main() {
cin >> n >> m >> s >> d;
for(int i = 0; i < n; i++) {
for(int j = 0; j < n; j++) {
dis[i][j] = inf;
}
}
for(int i = 0; i < n; i++) {
scanf("%d", &val[i]);
sum[i] = val[i];
sumpath[i] = 1;
to[i] = inf;
}
for(int i = 0; i < m; i++) {
scanf("%d%d%d", &u, &v, &len);
dis[u][v] = len;
dis[v][u] = len;
}
Dijstr();
printf("%d %d\n", sumpath[d], sum[d]);
int t = d, k = 0;
path[k++] = d;
while(t != s) {
t = pre[t];
path[k++] = t;
}
for(int i = k-1; i >= 0; i--) {
printf(i == k-1 ? "%d" : " %d", path[i]);
}
printf("\n");
return 0;
}
L2-002 鏈表去重
解法:思維題,拿結構體去模擬
代碼:
#include<bits/stdc++.h>
using namespace std;
struct lianbiao {
int now, num, next, k;
}l[200010];
int vis[100010];
int cmp(lianbiao a, lianbiao b) {
if(a.k < b.k) return 1;
return 0;
}
int main() {
int maxn = 100000;
int begin, n, a, b, c;
scanf("%d%d", &begin, &n);
for(int i = 0; i < maxn*2; i++) {
l[i].k = maxn * 2;
}
int num1 = 0, num2 = 0;
for(int i = 0; i < n; i++) {
scanf("%d%d%d", &a, &b, &c);
l[a].now = a;
l[a].num = b;
l[a].next = c;
}
for(int i = begin; i != -1; i = l[i].next) {
if(vis[abs(l[i].num)] == 0) {
l[i].k = num1;
vis[abs(l[i].num)] = 1;
num1++;
} else {
l[i].k = maxn + num2;
num2++;
}
}
sort(l, l+maxn*2, cmp);
for(int i = 0; i < num1+num2; i++) {
if(i == num1+num2-1) printf("%05d %d -1\n", l[i].now, l[i].num);
else if(i == num1-1) printf("%05d %d -1\n", l[i].now, l[i].num);
else
printf("%05d %d %05d\n", l[i].now, l[i].num, l[i+1].now);
}
return 0;
}
L2-003 月餅
解法:結構體排序
坑點:最好也有double存庫存和總價,否則可能會因爲浮點誤差WA在測試點2。
代碼:
#include<bits/stdc++.h>
using namespace std;
int n, d;
double ans = 0;
struct yuebing {
double sum, value;
}y[1010];
int cmp(yuebing a, yuebing b) {
if(a.value/a.sum > b.value/b.sum) return 1;
return 0;
}
int main() {
cin >> n >> d;
for(int i = 0; i < n; i++)
cin >> y[i].sum;
for(int i = 0; i < n; i++)
cin >> y[i].value;
sort(y, y+n, cmp);
for(int i = 0; i < n; i++) {
if(d == 0) break;
if(d >= y[i].sum) {
ans += y[i].value;
d -= y[i].sum;
} else {
ans += y[i].value*d/y[i].sum;
d = 0;
}
}
printf("%.2lf\n", ans);
return 0;
}
L2-004 搜索樹判斷
解法:二叉樹建樹、遍歷
代碼:(自己太菜了只拿了17分,後續有空再補補這題吧)
#include<bits/stdc++.h>
using namespace std;
int a[1010], tree[1010], f[1010], k;
int flag1, flag2, ceng;
void build(int l, int r) {
if(l > r) return;
tree[k++] = a[l];
int t = (r - l) / 2;
build(l+t+1, r);
build(l+1, l+t);
}
void judgebuild1(int l, int r) {//判斷是不是左小右大
int t = (r - l) / 2;
int ll = a[l+1];
int rr = a[l+t+1];
if(f[l+1]) return;//如果左右孩子已被使用就返回
f[l+1] = 1;//記錄左右孩子已被使用
if(f[l+t+1]) return;
f[l+t+1] = 1;
if(ll >= a[l] || rr < a[l]) flag1 = 1;
judgebuild1(l+1, l+t);
judgebuild1(l+t+1, r);
}
void judgebuild2(int l, int r) {
int t = (r - l) / 2;
int ll = a[l+1];
int rr = a[l+t+1];
if(f[l+1]) return;
f[l+1] = 1;
if(f[l+t+1]) return;
f[l+t+1] = 1;
if(ll < a[l] || rr >= a[l]) flag2 = 1;
judgebuild1(l+1, l+t);
judgebuild1(l+t+1, r);
}
int main() {
int n;
flag1 = 0;
flag2 = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
ceng = 0;
for(int i = 0; i <= n; i++) {
int tmp = pow(2, i);
if(tmp > n) break;
ceng++;
}
k = 0;
memset(f, 0, sizeof(f));
f[1] = 1;
judgebuild1(1, n);
memset(f, 0, sizeof(f));
f[1] = 1;
judgebuild2(1, n);
if(flag1 && flag2) printf("NO\n");
else {
build(1, n);
printf("YES\n");
for(int i = k-1; i >= 0; i--) {
printf(i == k-1 ? "%d" : " %d", tree[i]);
}
printf("\n");
}
return 0;
}
L2-005 集合相似度
解法:nc就是兩個集合分別去重後交集的元素個數,nt就是兩個集合直接並起來再去重後的元素個數。
坑點:每個集合先預處理存進set裏,算nc時應該遍歷集合1,然後用集合2調find方法來查找是否有集合1的某項值(即交集),查找速度O(logN),算nt時就可以用兩個集合總元素個數-兩個集合交集元素個數,就不需要遍歷然後全部插進set了,否則會超時。
代碼:
#include<bits/stdc++.h>
using namespace std;
int n, k, num, t, a, b, nc, nt;
set<int> s[55];
int main() {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> k;
for(int j = 0; j < k; j++) {
cin >> num;
s[i].insert(num);
}
}
cin >> t;
while(t--) {
nc = 0, nt = 0;
cin >> a >> b;
set<int>::iterator it;
for(it = s[a].begin(); it != s[a].end(); it++)
if(s[b].find(*it) != s[b].end()) nc++;
nt = s[a].size() + s[b].size() - nc;
printf("%.2lf%\n", nc*100*1.0/nt);
}
return 0;
}
L2-006 樹的遍歷
解法:裸二叉樹建樹、遍歷
代碼:
#include<bits/stdc++.h>
using namespace std;
int a[50], b[50], n;
map<int, int> L, R;
int build(int l1, int r1, int l2, int r2) {//後序, 中序
if(l1 > r1) return 0;
int root = a[r1];
int i;
for(i = l2; i <= r2; i++) {
if(b[i] == root) break;
}
if(i <= r2) {
int len = i - l2;
L[root] = build(l1, l1+len-1, l2, i-1);
R[root] = build(l1+len, r1-1, i+1, r2);
}
return root;
}
void bfs(int root) {
queue<int> q;
q.push(root);
int cnt = 0;
while(!q.empty()) {
int num = q.front();
q.pop();
printf(cnt == 0 ? "%d" : " %d", num);
cnt++;
if(L[num]) q.push(L[num]);
if(R[num]) q.push(R[num]);
}
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for(int i = 1; i <= n; i++) {
scanf("%d", &b[i]);
}
int root = build(1, n, 1, n);
bfs(root);
return 0;
}
L2-007 家庭房產
解法:並查集
代碼:
#include<bits/stdc++.h>
using namespace std;
int n, m, pre[10010], num[10010], area[10010], cc, k[10010], q, u, v, tot[10010], f[10010];
int t, s, coun;
vector<int> children[10010];
int bianhao[10010], fa[10010], mo[10010];
struct family {
int bh, sum;
double avet, aves;
}c[10010];
int find(int x) {
if(x == pre[x]) return pre[x];
return pre[x] = find(pre[x]);
}
void join(int x, int y) {
int fx = find(x), fy = find(y);
if(fx != fy) {
if(fx < fy) {//小的點作爲根
pre[fy] = fx;
num[fx] += num[fy];
area[fx] += area[fy];
tot[fx] += tot[fy];
} else {
pre[fx] = fy;
num[fy] += num[fx];
area[fy] += area[fx];
tot[fy] += tot[fx];
}
}
}
int cmp(family a, family b) {
if(a.aves > b.aves) return 1;
else if(a.aves == b.aves && a.bh < b.bh) return 1;
return 0;
}
int main() {
for(int i = 0; i < 10010; i++) {
pre[i] = i;
num[i] = 1;
}
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d%d%d%d", &bianhao[i], &fa[i], &mo[i], &k[i]);
f[bianhao[i]] = 1;
for(int j = 0; j < k[i]; j++) {
scanf("%d", &cc);
children[i].push_back(cc);
f[cc] = 1;
}
scanf("%d%d", &t, &s);
tot[bianhao[i]] += t;
area[bianhao[i]] += s;
}
for(int i = 0; i < n; i++) {
if(fa[i] != -1) {
f[fa[i]] = 1;
join(bianhao[i], fa[i]);
}
if(mo[i] != -1) {
f[mo[i]] = 1;
join(bianhao[i], mo[i]);
}
for(int j = 0; j < k[i]; j++) {
join(bianhao[i], children[i][j]);
}
}
coun = 0;
for(int i = 0; i < 10010; i++) {
if(f[find(i)]) {
c[coun].bh = find(i);
c[coun].sum = num[find(i)];
c[coun].avet = tot[find(i)] * 1.0 / num[find(i)];
c[coun].aves = area[find(i)] * 1.0 / num[find(i)];
coun++;
f[find(i)] = 0;
}
}
sort(c, c+coun, cmp);
printf("%d\n", coun);
for(int i = 0; i < coun; i++) {
printf("%04d %d %.3lf %.3lf\n", c[i].bh, c[i].sum, c[i].avet, c[i].aves);
}
return 0;
}
L2-008 最長對稱子串
解法:模擬
代碼:
#include<bits/stdc++.h>
using namespace std;
int main() {
string s;
getline(cin, s);
int maxlen = 1, slen = s.size(), flag = 0;
for(int len = slen; len > 1; len--) {
for (int i = 0; i < slen-len+1; i++) {
int p = 0;
for(int j = i; j < i+len; j++) {
if(s[j] != s[i+len-(j-i+1)]) {
p = 1;
break;
}
}
if(p == 0) {
flag = 1;
maxlen = len;
break;
}
}
if (flag == 1) break;
}
printf("%d\n", maxlen);
return 0;
}
L2-009 搶紅包
解法:模擬,計算
代碼:
#include<bits/stdc++.h>
using namespace std;
struct hongbao {
int id, num;
double get;
} h[10005];
int cmp(hongbao a, hongbao b) {
if(a.get > b.get) return 1;
if(a.get == b.get && a.num > b.num) return 1;
if(a.get == b.get && a.num == b.num && a.id < b.id) return 1;
return 0;
}
int main() {
int n, k, a, b;
cin >> n;
for(int i = 0; i <= n; i++) {
h[i].id = i;
h[i].num = 0;
h[i].get = 0;
}
for(int i = 1; i <= n; i++) {
cin >> k;
for(int j = 0; j < k; j++) {
cin >> a >> b;
h[a].get += b;
h[i].get -= b;
h[a].num++;
}
}
sort(h+1, h+n+1, cmp);
for(int i = 1; i <= n; i++)
printf("%d %.2lf\n", h[i].id, h[i].get/100);
return 0;
}
L2-010 排座位
解法:模擬
代碼:
#include<bits/stdc++.h>
using namespace std;
int a[110][110], n, m, k, u, v, r;
int pre[110];
int find(int x) {
if(x == pre[x]) return pre[x];
return pre[x] = find(pre[x]);
}
void join(int x, int y) {
int fx = find(x), fy = find(y);
if(fx != fy) {
pre[fx] = fy;
}
}
int main() {
scanf("%d%d%d", &n, &m, &k);
for(int i = 1; i <= n; i++) {
pre[i] = i;
}
for(int i = 0; i < m; i++) {
scanf("%d%d%d", &u, &v, &r);
a[u][v] = r;
a[v][u] = r;
if(r == 1) join(u, v);
}
while(k--) {
scanf("%d%d", &u, &v);
if(a[u][v] == -1) {//有敵對關係
if(find(u) == find(v)) printf("OK but...\n");
else
printf("No way\n");
} else {
if(find(u) == find(v)) printf("No problem\n");
else
printf("OK\n");
}
}
return 0;
}
L2-011 玩轉二叉樹
解法:裸二叉樹建樹、遍歷
代碼:
#include<bits/stdc++.h>
using namespace std;
int a[50], b[50], n;
map<int, int> L, R;
int build(int l1, int r1, int l2, int r2) {//中序, 前序
if(l1 > r1) return 0;
int root = b[l2];
int i;
for(i = l1; i <= r1; i++) {
if(a[i] == root) break;
}
if(i <= r1) {
int len = i - l1;
L[root] = build(i+1, r1, l2+len+1, r2);
R[root] = build(l1, i-1, l2+1, l2+len);
}
return root;
}
void bfs(int root) {
queue<int> q;
q.push(root);
int cnt = 0;
while(!q.empty()) {
int num = q.front();
q.pop();
printf(cnt == 0 ? "%d" : " %d", num);
cnt++;
if(L[num]) q.push(L[num]);
if(R[num]) q.push(R[num]);
}
}
int main() {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
for(int i = 1; i <= n; i++) {
scanf("%d", &b[i]);
}
int root = build(1, n, 1, n);
bfs(root);
return 0;
}
L2-012 關於堆的判斷
解法:太難了,後續有時間再補
代碼:無
L2-013 紅色警報
解法:並查集
代碼:
#include<bits/stdc++.h>
using namespace std;
int n, m, pre[510], d[510], path[510][510], u, v, q, city, f[510], a[5100], b[5100];
int find(int x) {
if(x == pre[x]) return pre[x];
return pre[x] = find(pre[x]);
}
void join(int x, int y) {
int fx = find(x), fy = find(y);
if(fx != fy) {
pre[fx] = fy;
}
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 0; i < n; i++) {
pre[i] = i;
f[i] = 0;
}
for(int i = 0; i < m; i++) {
scanf("%d%d", &u, &v);
a[i] = u;
b[i] = v;
join(u, v);
}
set<int> s;
for(int i = 0; i < n; i++) {
s.insert(find(i));
}
scanf("%d", &q);
int sum = q;
while(q--) {
scanf("%d", &city);
int old = s.size();
f[city] = 1;
s.clear();
for(int i = 0; i < n; i++) {
pre[i] = i;
}
for(int i = 0; i < m; i++) {
if(f[a[i]] == 1 || f[b[i]] == 1) continue;
join(a[i], b[i]);
}
for(int i = 0; i < n; i++) {
s.insert(find(i));
}
if(s.size() - old > 1) printf("Red Alert: City %d is lost!\n", city);
else {
printf("City %d is lost.\n", city);
}
}
if(s.size() == n) printf("Game Over.\n");
return 0;
}
L2-014 列車調度
解法:模擬
代碼:
#include<bits/stdc++.h>
using namespace std;
int a[100010];
int main() {
int n;
set<int> s;
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
for(int i = 0; i < n; i++) {
if(s.upper_bound(a[i]) != s.end()) {
s.erase(s.upper_bound(a[i]));
}
s.insert(a[i]);
}
printf("%d\n", s.size());
return 0;
}
L2-015 互評成績
解法:模擬
代碼:
#include<bits/stdc++.h>
using namespace std;
int n, k, m, sum, maxn, minn, score;
double ans[10010];
int main() {
cin >> n >> k >> m;
for(int i = 0; i < n; i++) {
sum = 0;
maxn = 0;
minn = 100;
for(int j = 0; j < k; j++) {
cin >> score;
sum += score;
maxn = max(maxn, score);
minn = min(minn, score);
}
ans[i] = (sum - maxn - minn) * 1.0 / (k - 2);
}
sort(ans, ans+n);
for(int i = n-m; i < n; i++)
printf(i == n-m ? "%.3lf" : " %.3lf", ans[i]);
return 0;
}
L2-016 願天下有情人都是失散多年的兄妹
解法:遞歸分治
代碼:
#include<bits/stdc++.h>
using namespace std;
int f[100000], m[100000], x[100000];
int flag;
map<int, int> qinqi;
void judge(int num, int k) {
if(k >= 5) return;
if(f[num] != -1) {
qinqi[f[num]] = 1;
judge(f[num], k+1);
}
if(m[num] != -1) {
qinqi[m[num]] = 1;
judge(m[num], k+1);
}
}
int judgeother(int num, int k) {
if(k >= 5) return 0;
if(f[num] != -1) {
if(qinqi[f[num]] == 1) return 1;
if(judgeother(f[num], k+1) == 1) return 1;
}
if(m[num] != -1) {
if(qinqi[m[num]] == 1) return 1;
if(judgeother(m[num], k+1) == 1) return 1;
}
return 0;
}
int main() {
int n, q, a, b, p, fa, mo;
memset(f, -1, sizeof(f));
memset(m, -1, sizeof(m));
char sex;
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%05d %c %05d %05d", &p, &sex, &fa, &mo);
f[p] = fa;
m[p] = mo;
if(sex == 'M') x[p] = 1;
else
x[p] = 0;
if(fa != -1) x[fa] = 1;
if(mo != -1) x[mo] = 0;
}
scanf("%d", &q);
while(q--) {
scanf("%d%d", &a, &b);
if(x[a] == x[b]) printf("Never Mind\n");
else {
flag = 0;
qinqi.clear();
judge(a, 1);
if(judgeother(b, 1) == 1) printf("No\n");
else
printf("Yes\n");
}
}
return 0;
}
L2-017 人以羣分
解法:模擬
代碼:
#include<bits/stdc++.h>
using namespace std;
int a[100010];
int main() {
int n, t, sum1 = 0, sum2 = 0;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
sort(a+1, a+n+1);
if(n % 2 == 0) {
for(int i = 1; i <= n; i++) {
if(i <= n/2) sum1 += a[i];
else
sum2 += a[i];
}
printf("Outgoing #: %d\nIntroverted #: %d\nDiff = %d\n", n/2, n/2, sum2-sum1);
} else {
for(int i = 1; i <= n; i++) {
if(i <= n/2) sum1 += a[i];
else
sum2 += a[i];
}
printf("Outgoing #: %d\nIntroverted #: %d\nDiff = %d\n", n-n/2, n/2, sum2-sum1);
}
return 0;
}
L2-018 多項式A除以B
解法:數學計算題,告辭
代碼:無
L2-019 悄悄關注
解法:模擬
代碼:
#include<bits/stdc++.h>
using namespace std;
int main() {
int n, m, sum = 0, k, flag = 0;
string name;
map<string, bool>yonghu;
cin >> n;
for(int i = 0; i < n; i++) {
cin >> name;
yonghu[name] = true;
}
cin >> m;
map<string, int>dianzan;
for(int i = 0; i < m; i++) {
cin >> name >> k;
dianzan[name] = k;
sum += k;
}
map<string, int>::iterator iter;
for(iter = dianzan.begin(); iter != dianzan.end(); iter++)
if(iter->second > sum*1.0/m && yonghu[iter->first] != true) {
flag = 1;
cout << iter->first << endl;
}
if(!flag) cout << "Bing Mei You" << endl;
return 0;
}
L2-020 功夫傳人
解法:遞歸
代碼:
#include<bits/stdc++.h>
using namespace std;
int dedao[100010];
vector<int> v[100010];//存徒弟
int n, k, num;
double z, r, sum;
void dfs(int id, double tmp) {
int len = v[id].size();
for(int i = 0; i < len; i++) {
if(dedao[v[id][i]]) {//得道
sum += tmp*(100-r)*dedao[v[id][i]]/100;
} else {
dfs(v[id][i], tmp*(100-r)/100);
}
}
}
int main() {
sum = 0;
scanf("%d%lf%lf", &n, &z, &r);
for(int i = 0; i < n; i++) {
scanf("%d", &k);
if(k == 0) {
scanf("%d", &num);
dedao[i] = num;
} else {
for(int j = 0; j < k; j++) {
scanf("%d", &num);
v[i].push_back(num);
}
}
}
if(dedao[0] != 0) sum += dedao[0] * z;//祖師爺得道
dfs(0, z);
printf("%d\n", (int)sum);
return 0;
}
L2-021 點贊狂魔
解法:模擬
代碼:
#include<bits/stdc++.h>
using namespace std;
int n, k, id;
struct dianzan {
string name;
int sum;
double avg;
}d[105];
int cmp(dianzan a, dianzan b) {
if(a.sum > b.sum) return 1;
else if(a.sum == b.sum && a.avg < b.avg) return 1;
return 0;
}
int main() {
cin >> n;
for(int i = 0; i < n; i++) {
cin >> d[i].name >> k;
set<int> s;
for(int j = 0; j < k; j++) {
cin >> id;
s.insert(id);
}
d[i].sum = s.size();
d[i].avg = k * 1.0 / s.size();
}
sort(d, d+n, cmp);
if(n < 3) {
cout << d[0].name;
int i;
for(i = 1; i < n; i++)
cout << " " << d[i].name;
for(; i < 3; i++)
cout << " -";
} else {
cout << d[0].name;
for(int i = 1; i < 3; i++)
cout << " " << d[i].name;
}
return 0;
}
L2-022 重排鏈表
解法:思維題,結構體模擬
代碼:
#include<bits/stdc++.h>
using namespace std;
struct lianbiao {
int now, num, next, id;
} l[100010];
int cmp(lianbiao a, lianbiao b) {
if(a.id < b.id) return 1;
return 0;
}
int main() {
int begin, n, k = 1, now, num, next;
scanf("%d%d", &begin, &n);
for(int i = 0; i < 100010; i++) {
l[i].id = 200000;
}
for(int i = 0; i < n; i++) {
scanf("%d%d%d", &now, &num, &next);
l[now].now = now;
l[now].num = num;
l[now].next = next;
}
for(int i = begin; i != -1; i = l[i].next) {
l[i].id = k;
k++;
}
sort(l, l+100010, cmp);
for(int i = 0; i < k-1; i++) {
if(i % 2 == 0) {
if(i == k-2) printf("%05d %d -1\n", l[k-2-i/2].now, l[k-2-i/2].num);
else
printf("%05d %d %05d\n", l[k-2-i/2].now, l[k-2-i/2].num, l[(i+1)/2].now);
} else {
if(i == k-2) printf("%05d %d -1\n", l[i/2].now, l[i/2].num);
else
printf("%05d %d %05d\n", l[i/2].now, l[i/2].num, l[k-2-(i+1)/2].now);
}
}
return 0;
}
L2-023 圖着色問題
解法:思維題
代碼:
#include<bits/stdc++.h>
using namespace std;
vector<int> v[510];
int color[510];
int main() {
int n, e, k, q, u1, u2;
scanf("%d%d%d", &n, &e, &k);
for(int i = 0; i < e; i++) {
scanf("%d%d", &u1, &u2);
v[u1].push_back(u2);
v[u2].push_back(u1);
}
scanf("%d", &q);
while(q--) {
set<int> s;
for(int i = 1; i <= n; i++) {
scanf("%d", &color[i]);
s.insert(color[i]);
}
if(s.size() != k) {
printf("No\n");
continue;
} else {
int flag = 0;
for(int i = 1; i <= n; i++) {
int len = v[i].size();
for(int j = 0; j < len; j++) {
if(color[i] == color[v[i][j]]) {
flag = 1;
break;
}
}
if(flag) break;
}
if(flag) printf("No\n");
else
printf("Yes\n");
}
}
return 0;
}
L2-024 部落
解法:裸並查集
代碼:
#include<bits/stdc++.h>
using namespace std;
int n, pre[10010], a[10010], k, q, u, v, f[10010];
int find(int x) {
if(x == pre[x]) return pre[x];
return pre[x] = find(pre[x]);
}
void join(int x, int y) {
int fx = find(x), fy = find(y);
if(fx != fy) {
pre[fx] = fy;
}
}
int main() {
int sum = 0;
scanf("%d", &n);
for(int i = 0; i < 10010; i++) {
pre[i] = i;
}
for(int i = 0; i < n; i++) {
scanf("%d", &k);
for(int j = 0; j < k; j++) {
scanf("%d", &a[j]);
if(f[a[j]] == 0) {
f[a[j]] = 1;
sum++;
}
if(j > 0) join(a[j], a[j-1]);
}
}
set<int> s;
for(int i = 0; i < 10010; i++) {
if(f[i]) s.insert(find(i));
}
printf("%d %d\n", sum, s.size());
scanf("%d", &q);
while(q--) {
scanf("%d%d", &u, &v);
if(find(u) == find(v)) printf("Y\n");
else
printf("N\n");
}
return 0;
}
L2-025 分而治之
解法:思維題
代碼:
#include<bits/stdc++.h>
using namespace std;
int n, m, pre[10010], a[10010], k, q, u, v, f[10010], num, t;
struct city {
int x, y;
} c[10010];
int main() {
int sum = 0;
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++) {
scanf("%d%d", &c[i].x, &c[i].y);
}
scanf("%d", &q);
while(q--) {
memset(f, 0, sizeof(f));
scanf("%d", &num);
for(int i = 0; i < num; i++) {
scanf("%d", &t);
f[t] = 1;
}
int cnt = 0;
for(int i = 0; i < m; i++) {
if(f[c[i].x] == 1 || f[c[i].y] == 1) continue;
cnt++;
}
if(cnt == 0) printf("YES\n");
else
printf("NO\n");
}
return 0;
}
L2-026 小字輩
解法:簡單bfs
代碼:
#include<bits/stdc++.h>
using namespace std;
vector<int> v[100010];
int n, num, root, f[100010], k, maxlevel;
struct people {
int bianhao;
int level;
}pp[100010];
void bfs(int level) {
queue<people> q;
people now, next;
now.bianhao = root;
now.level = 1;
q.push(now);
while(!q.empty()) {
now = q.front();
if(now.level > maxlevel) {
maxlevel = now.level;
k = 0;
}
if(now.level == maxlevel) f[k++] = now.bianhao;
q.pop();
int len = v[now.bianhao].size();
for(int i = 0; i < len; i++) {
next.bianhao = v[now.bianhao][i];
next.level = now.level + 1;
q.push(next);
}
}
}
int main() {
scanf("%d", &n);
maxlevel = 0;
for(int i = 1; i <= n; i++) {
scanf("%d", &num);
if(num == -1) root = i;
else
v[num].push_back(i);
}
bfs(1);
printf("%d\n", maxlevel);
sort(f, f+k);
for(int i = 0; i < k; i++) {
printf(i == 0 ? "%d" : " %d", f[i]);
}
printf("\n");
return 0;
}
L2-027 名人堂與代金券
解法:結構體排序
代碼:
#include<bits/stdc++.h>
using namespace std;
int a[10010];
struct st {
string name;
int score;
int rank;
} s[10010];
int cmp(st a, st b) {
if(a.score > b.score) return 1;
else if(a.score == b.score && a.name < b.name) return 1;
return 0;
}
int main() {
int n, g, k, sum = 0;
scanf("%d%d%d", &n, &g, &k);
for(int i = 0; i < n; i++) {
cin >> s[i].name >> s[i].score;
if(s[i].score >= 60 && s[i].score < g) sum += 20;
if(s[i].score >= g && s[i].score <= 100) sum += 50;
}
sort(s, s+n, cmp);
printf("%d\n", sum);
int m = 1, rm = 1, t = 0;
for(int i = 0; i < n; i++) {
if(i != 0 && s[i].score != s[i-1].score) m = i + 1;
s[i].rank = m;
}
for(int i = 0; i < n; i++) {
if(s[i].rank > k) break;
cout << s[i].rank << " " << s[i].name << " " << s[i].score << endl;
}
return 0;
}
L2-028 秀恩愛分得快
解法:一開始我是算出所有關係對的親密度然後直接查找,但是時間複雜度是m*k*k,是會超時的。需要換一種方法來避免不必要關係對的計算,就可以事先將每張照片出現的人存起來,我是存進set數組裏面,因爲後續需要查找某張照片裏面是否出現某個人的時候,set的find方法查找速度是比較快的。這裏需要預處理每個人的性別存進sex數組,後續可以通過編號來直接獲取性別,但是這裏要注意0的男女判斷,0代表男性,-0代表的是女性,因此輸入人的時候需要採用字符輸入的方式。給定兩個人要分別計算他們與別人的親密度的時候,只需要遍歷每張照片,當該照片中出現了該人的時候才計算親密度,且只需要計算該人與其他人的親密度不需要計算其他人與該人的親密度,這樣就不會超時了。
坑點:邏輯沒錯的話,很可能會出現輸出上的坑,特別要注意女性的0在輸出時是需要手動加負號的,比如查詢輸入的a爲-0時,a實際存儲的是0(不帶負號),爲了能夠輸出-0,就需要在輸出的時候給女性手動加負號 。另外提供兩組測試數據供大家測試:
input:
4 1
4 -0 1 -2 3
-0 1
output:
-0 1
input:
4 2
4 -0 1 -2 3
2 -0 3
1 -0
output:
1 -0
1 -2
-0 3
代碼:
#include<bits/stdc++.h>
using namespace std;
double p, maxwitha = 0, maxwithb = 0, re[1010][1010];
int sex[1010], cnt[1010], ansa[1010], ansb[1010];
set<int> s[1010];
int read() {
int x = 0, f = 1;
int ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') f = -1;//讀到了負號
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
x = x * 10 + (int)(ch - '0');
ch = getchar();
}
if(f == 1) sex[x] = 1;//男性標爲1,女性爲默認值0
return x;//返回該人的非負編號
}
int main() {
int n, m, a, b, num, numa = 0, numb = 0;
scanf("%d%d", &n, &m);
for(int i = 1; i <= m; i++) {
scanf("%d", &cnt[i]);
for(int j = 0; j < cnt[i]; j++) {
num = read();
s[i].insert(num);
}
}
scanf("%d%d", &a, &b);
for(int i = 1; i <= m; i++) {
p = 1.0 / cnt[i];
if(s[i].find(abs(a)) != s[i].end()) {
set<int>::iterator it;
for(it = s[i].begin(); it != s[i].end(); it++)
if(sex[abs(a)] != sex[*it]) re[abs(a)][*it] += p;
}
if(s[i].find(abs(b)) != s[i].end()) {
set<int>::iterator it;
for(it = s[i].begin(); it != s[i].end(); it++)
if(sex[abs(b)] != sex[*it]) re[abs(b)][*it] += p;
}
}
for(int i = 0; i < n; i++) {
if(re[abs(a)][i] > maxwitha) {
maxwitha = re[abs(a)][i];
numa = 0;
ansa[numa++] = i;
} else if(re[abs(a)][i] == maxwitha) {
ansa[numa++] = i;
}
if(re[abs(b)][i] > maxwithb) {
maxwithb = re[abs(b)][i];
numb = 0;
ansb[numb++] = i;
} else if(re[abs(b)][i] == maxwithb) {
ansb[numb++] = i;
}
}
//判斷a和b是否正是彼此親密度最高的一對,即與a與別人最高的親密度剛好等於a與b的親密度且b與別人最高的親密度剛好等於b與a的親密度
if(re[abs(a)][ansa[0]] == re[abs(a)][abs(b)] && re[abs(b)][ansb[0]] == re[abs(b)][abs(a)]) printf(sex[abs(a)] == 0 ? "-%d %d\n" : "%d -%d\n", abs(a), abs(b));
else {
for(int i = 0; i < numa; i++) {
if(sex[abs(a)]) printf("%d -%d\n", a, ansa[i]);
else
printf("-%d %d\n", abs(a), ansa[i]);
}
for(int i = 0; i < numb; i++) {
if(sex[abs(b)]) printf("%d -%d\n", b, ansb[i]);
else
printf("-%d %d\n", abs(b), ansb[i]);
}
}
return 0;
}
L2-029 特立獨行的幸福
解法:模擬。對未進行標記的數進行模擬,記錄該數迭代後的所有數,當結束迭代時,通過判斷最終迭代結果是否爲1來確定該數是不是幸福數,如果是,則只將迭代後的所有數標記爲0,將該數標記爲幸福數;如果不是,就把該數和迭代數都標記爲0。至於特立獨行性,因爲每次在判斷被依賴數之後,都會對依賴數標記爲0,所以在for循環結束後,就只會保留下特立獨行的幸福數(被依賴數)。
坑點:小於10的數裏面只有7是特立獨行的幸福數。
代碼:
#include<bits/stdc++.h>
using namespace std;
int a, b, tmp, cnt, t, flag, f[10010], vis[10010];
int isprimer(int n) {
for(int i = 2; i <= sqrt(n); i++)
if(n % i == 0) return 0;
return 1;
}
int main() {
memset(f, -1, sizeof(f));
cin >> a >> b;
for(int i = a; i <= b; i++) {
if(f[i] != -1) continue;
memset(vis, 0, sizeof(vis));
vector<int> v;
tmp = i;
cnt = 0;
v.push_back(i);
do {
vis[tmp] = 1;
t = tmp;
tmp = 0;
while(t) {
tmp += (t % 10) * (t % 10);
t /= 10;
}
v.push_back(tmp);
cnt++;
} while(!vis[tmp] && tmp != 1);
if(tmp == 1) {
f[i] = cnt;
if(isprimer(i)) f[i] *= 2;
for(int j = 1; j < v.size(); j++)
f[v[j]] = 0;
} else {
for(int j = 0; j < v.size(); j++)
f[v[j]] = 0;
}
}
flag = 0;
for(int i = a; i <= b; i++) {
if(f[i]) {
flag = 1;
cout << i << " " << f[i] << endl;
}
}
if(!flag) cout << "SAD" << endl;
return 0;
}
L2-030 冰島人
解法:耐心讀懂題意就好了。注意這句話----“所謂“五代以內無公共祖先”是指兩人的公共祖先(如果存在的話)必須比任何一方的曾祖父輩分高。”,意思就是說兩人的公共祖先不能是任何一人的上三代以內(包括第三代也包括自己)。
做起來的話,因爲需要存儲每個人的父親,首先需要給每個人編號,另外尋找父親的話,由於不能用n^2的方法遍歷找父親(會超時),因此可以用兩個map容器來存每個人對應的編號,一個map存名另一個存姓(因爲後續查詢時的姓是不帶後綴的因此可以提取姓後綴子串得到姓)作爲鍵,該人對應的編號作爲值。還可以預處理一下每個人的性別,方便後面直接判斷。在查詢的時候,也可以用一個map來存儲祖先編號和祖先代數,這樣就可以在發現存在共同祖先的時候,直接通過判斷祖先代數來得到答案。
坑點:給定查詢的兩個人,有可能某個人是另一個人的直系祖先;如果兩個人存在公共祖先,公共祖先是一個人的上10代祖先,是另一個人的上1代祖先,那麼也是No的。(測試點3、6答案錯誤)
把cin改成scanf的輸入。(測試點6超時)
代碼:
#include<bits/stdc++.h>
using namespace std;
int n, t, pre[100010], sex[100010];
string s1[100010], s2[100010], fn1, ln1, fn2, ln2;
map<string, int> firstname, lastname;
int main() {
scanf("%d", &n);
getchar();
for(int i = 1; i <= n; i++) {
cin >> s1[i] >> s2[i];
firstname[s1[i]] = i;
if(s2[i].size() > 4 && s2[i].substr(s2[i].size()-4, s2[i].size()) == "sson") {
sex[i] = 1;
lastname[s2[i].substr(0, s2[i].size()-4)] = i;
} else if(s2[i].size() > 7 && s2[i].substr(s2[i].size()-7, s2[i].size()) == "sdottir") {
lastname[s2[i].substr(0, s2[i].size()-7)] = i;
} else if(s2[i][s2[i].size()-1] == 'm') {
sex[i] = 1;
lastname[s2[i].substr(0, s2[i].size()-1)] = i;
} else {
lastname[s2[i].substr(0, s2[i].size()-1)] = i;
}
}
for(int i = 1; i <= n; i++) {
if(s2[i].size() > 4 && s2[i].substr(s2[i].size()-4, s2[i].size()) == "sson") {
if(firstname[s2[i].substr(0, s2[i].size()-4)] != 0) pre[i] = firstname[s2[i].substr(0, s2[i].size()-4)];
else
pre[i] = -1;
} else if(s2[i].size() > 7 && s2[i].substr(s2[i].size()-7, s2[i].size()) == "sdottir") {
if(firstname[s2[i].substr(0, s2[i].size()-7)] != 0) pre[i] = firstname[s2[i].substr(0, s2[i].size()-7)];
else
pre[i] = -1;
} else {
pre[i] = -1;
}
}
scanf("%d", &t);
getchar();
while(t--) {
cin >> fn1 >> ln1 >> fn2 >> ln2;
if(!firstname[fn1] || !firstname[fn2] || !lastname[ln1] || !lastname[ln2]) printf("NA\n");
else if(sex[firstname[fn1]] == sex[firstname[fn2]]) printf("Whatever\n");
else {
map<int, int> f;
int d = 1, flag = 0, now = pre[firstname[fn1]];
f[firstname[fn1]] = 1;
while(now != -1) {
d++;
if(now == firstname[fn2]) {//2是1的直系
flag = 1;
break;
} else {
f[now] = d;
}
now = pre[now];
}
d = 1;
now = pre[firstname[fn2]];
while(now != -1 && !flag) {
d++;
if(f[now] > 0 && (f[now] < 5 || d < 5)) {//存在公共祖先,且是某一方的上三代以內
flag = 1;
break;
}
now = pre[now];
}
if(flag) printf("No\n");
else
printf("Yes\n");
}
}
return 0;
}
L2-031 深入虎穴
解法:簡單bfs,記錄每次出隊的門,最後一次出隊的門則是答案。
坑點:入口不一定是1號門,要判斷一下入口門的編號,入口意味着沒有門在它前面。
代碼:
#include<bits/stdc++.h>
using namespace std;
int n, k, num, root, ans, f[100010];
vector<int> d[100010];
void bfs(int s) {
queue<int> q;
q.push(s);
while(!q.empty()) {
int now = q.front();
q.pop();
ans = now;
for(int i = 0; i < d[now].size(); i++)
q.push(d[now][i]);
}
cout << ans << endl;
}
int main() {
cin >> n;
for(int i = 1; i <= n; i++) {
cin >> k;
for(int j = 0; j < k; j++) {
cin >> num;
d[i].push_back(num);
f[num] = 1;
}
}
for(int i = 1; i <= n; i++)
if(!f[i]) {
root = i;
break;
}
bfs(root);
return 0;
}
L2-032 彩虹瓶
解法:用棧模擬
代碼:
#include<bits/stdc++.h>
using namespace std;
int n, m, num, now, k, flag, vis[1010];
int main() {
cin >> n >> m >> k;
while(k--) {
memset(vis, 0, sizeof(vis));
flag = 0;
stack<int> s;
now = 1;
for(int i = 0; i < n; i++) {
cin >> num;
if(flag) continue;
if(num == now) {
now++;
while(!s.empty() && now == s.top()) {
now++;
s.pop();
}
if(vis[now]) flag = 1;
} else {
if(s.size() >= m) flag = 1;
else {
s.push(num);
vis[num] = 1;
}
}
}
if(flag) cout << "NO" << endl;
else
cout << "YES" << endl;
}
return 0;
}