2012-09-26 22:19:29Morris
[ITSA] 17th 總解答
第一題 模擬
#include <stdio.h>
int main() {
int n;
while(scanf("%d", &n) == 1) {
int sk1[100], sk2[100];
int idx = -1, i;
int tot = 0, p = 0, v, w;
int vv[100], ww[100];
for(i = n-1; i >= 0; i--)
scanf("%d %d", &vv[i], &ww[i]);
for(i = 0; i < n; i++) {
v = vv[i], w = ww[i];
if(tot+w <= 20) {
++idx;
sk1[idx] = v, sk2[idx] = w;
tot += w, p += v;
} else {
if((double)sk1[idx]/sk2[idx] > (double)v/w) continue;
if((double)sk1[idx]/sk2[idx] < (double)v/w) {
tot -= sk2[idx], p -= sk1[idx];
sk1[idx] = v, sk2[idx] = w;
tot += w, p += v;
}
}
}
printf("%d %d\n", p, tot);
}
return 0;
}
第二題 求最大獨立集 dfs 回朔求解
#include <stdio.h>
#include <string.h>
int ans = 0, n, m;
int g[105][105], gt[105];
int used[105] = {};
void dfs(int idx, int v) {
if(v > ans) ans = v;
if(v + n-idx < ans)
return;
if(idx == n)
return;
int i = 0, can = 0;
for(i = 0; i < gt[idx]; i++) {
if(used[g[idx][i]])
break;
}
if(i == gt[idx]) can = 1;
if(can) {
used[idx] = 1;
dfs(idx+1, v+1);
used[idx] = 0;
}
dfs(idx+1, v);
}
int main() {
int i, x, y;
while(scanf("%d %d", &m, &n) == 2) {
for(i = 0; i < m; i++) {
scanf("%d %d", &x, &y);
g[x][gt[x]++] = y;
g[y][gt[y]++] = x;
}
ans = 0;
dfs(0, 0);
printf("%d\n", ans);
}
return 0;
}
第三題 時間計算, 模擬
#include <cstdio>
int main() {
int t;
scanf("%d", &t);
while(t--) {
int H, M, h, m, s, d;
scanf("%d %d %d %d %d %d", &H, &M, &h, &m, &s, &d);
H = H*60+M;
h = h*60+m;
H = h-H;
if(H%60) H = H/60+1;
else H = H/60;
printf("%d\n", H*d*s);
}
return 0;
}
第四題 前序運算式, 建造一棵運算樹 (其實我忘記他的學術名稱), 總之只有葉節點是值, 非葉節點都是運算子(+-*/), 接著藉由樹的走訪可以輸出跟計算答案
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string.h>
using namespace std;
typedef struct {
int l, r;
int num;
int flag;
} Node;
Node Nd[1000];
int size;
stringstream sin;
void build(int idx) {
string tmp;
sin >> tmp;
if(tmp[0] > '9' || tmp[0] < '0' &&) {
Nd[idx].num = tmp[0];
Nd[idx].flag = 0;
size++;
Nd[idx].l = size;
build(size);
size++;
Nd[idx].r = size;
build(size);
} else {
stringstream nin;
nin << tmp;
int v;
nin >> v;
Nd[idx].num = v;
Nd[idx].flag = 1;
}
}
void travel(int idx) {
if(!Nd[idx].flag) {
if(!Nd[Nd[idx].l].flag)
printf("(");
travel(Nd[idx].l);
if(!Nd[Nd[idx].l].flag)
printf(")");
if(Nd[idx].num == '+') {
printf("+");
} else
if(Nd[idx].num == '*') {
printf("*");
} else
if(Nd[idx].num == '/') {
printf("/");
} else {
printf("-");
}
if(!Nd[Nd[idx].r].flag)
printf("(");
travel(Nd[idx].r);
if(!Nd[Nd[idx].r].flag)
printf(")");
} else {
printf("%d", Nd[idx].num);
}
}
double calu(int idx) {
if(Nd[idx].flag)
return Nd[idx].num;
if(Nd[idx].num == '+') {
return calu(Nd[idx].l)+calu(Nd[idx].r);
} else
if(Nd[idx].num == '*') {
return calu(Nd[idx].l)*calu(Nd[idx].r);
} else
if(Nd[idx].num == '/') {
return calu(Nd[idx].l)/calu(Nd[idx].r);
} else {
return calu(Nd[idx].l)-calu(Nd[idx].r);
}
}
int main() {
int t;
scanf("%d", &t);
getchar();
string line;
while(t--) {
getline(cin, line);
memset(Nd, 0, sizeof(Nd));
sin.clear();
sin << line;
size = 1;
build(1);
travel(1);
printf("=%.2lf\n", calu(1));
}
return 0;
}
第五題 這次最難的題目, 樹形 DP
兩次 dfs
1st dfs :
得到由下而上的最大高度 (要記錄第一高 第二高),
意即 得到每個節點的 subtree 的高度
2nd dfs :
將父節點高度轉過來, 這時要注意, 如果第一高是從這個節點接上去的, 那麼就抓第二高+1
#include <stdio.h>
#include <algorithm>
#include <vector>
#define oo 0xfffffff
using namespace std;
vector<int> edge[95005];
int dp_down[95005][2], dp_up[95005];
int used[95005];
void dfs(int nd) {
for(vector<int>::iterator i = edge[nd].begin(); i != edge[nd].end(); i++) {
if(used[*i] == 0) {
used[*i] = 1;
dfs(*i);
if(dp_down[*i][0]+1 > dp_down[nd][1])
dp_down[nd][1] = dp_down[*i][0]+1;
if(dp_down[nd][1] > dp_down[nd][0])
swap(dp_down[nd][0], dp_down[nd][1]);
}
}
}
void dfs2(int nd, int v) {
dp_up[nd] = v;
for(vector<int>::iterator i = edge[nd].begin(); i != edge[nd].end(); i++) {
if(used[*i] == 0) {
used[*i] = 1;
int hv;
if(dp_down[*i][0]+1 != dp_down[nd][0])
hv = dp_down[nd][0];
else
hv = dp_down[nd][1];
hv = max(hv, dp_up[nd]);
dfs2(*i, hv+1);
}
}
}
int main() {
int n, m, i, y;
while(scanf("%d", &n) == 1) {
for(i = 1; i <= n; i++) {
edge[i].clear();
dp_down[i][0] = 0;
dp_down[i][1] = 0;
dp_up[i] = 0;
used[i] = 0;
}
int x, y;
for(i = 1; i < n; i++) {
scanf("%d %d", &x, &y);
x++, y++;
edge[x].push_back(y);
edge[y].push_back(x);
}
used[1] = 1;
dfs(1);
for(i = 1; i <= n; i++) used[i] = 0;
used[1] = 1;
dfs2(1, 0);
int root[95001], best = oo;
for(i = 1; i <= n; i++) {
root[i] = max(max(dp_down[i][0], dp_down[i][1]), dp_up[i]);
best = min(best, root[i]);
}
for(i = 1; i <= n; i++)
if(root[i] == best) {
printf("%d\n", i-1);
break;
}
}
return 0;
}
#include <stdio.h>
int main() {
int n;
while(scanf("%d", &n) == 1) {
int sk1[100], sk2[100];
int idx = -1, i;
int tot = 0, p = 0, v, w;
int vv[100], ww[100];
for(i = n-1; i >= 0; i--)
scanf("%d %d", &vv[i], &ww[i]);
for(i = 0; i < n; i++) {
v = vv[i], w = ww[i];
if(tot+w <= 20) {
++idx;
sk1[idx] = v, sk2[idx] = w;
tot += w, p += v;
} else {
if((double)sk1[idx]/sk2[idx] > (double)v/w) continue;
if((double)sk1[idx]/sk2[idx] < (double)v/w) {
tot -= sk2[idx], p -= sk1[idx];
sk1[idx] = v, sk2[idx] = w;
tot += w, p += v;
}
}
}
printf("%d %d\n", p, tot);
}
return 0;
}
第二題 求最大獨立集 dfs 回朔求解
#include <stdio.h>
#include <string.h>
int ans = 0, n, m;
int g[105][105], gt[105];
int used[105] = {};
void dfs(int idx, int v) {
if(v > ans) ans = v;
if(v + n-idx < ans)
return;
if(idx == n)
return;
int i = 0, can = 0;
for(i = 0; i < gt[idx]; i++) {
if(used[g[idx][i]])
break;
}
if(i == gt[idx]) can = 1;
if(can) {
used[idx] = 1;
dfs(idx+1, v+1);
used[idx] = 0;
}
dfs(idx+1, v);
}
int main() {
int i, x, y;
while(scanf("%d %d", &m, &n) == 2) {
for(i = 0; i < m; i++) {
scanf("%d %d", &x, &y);
g[x][gt[x]++] = y;
g[y][gt[y]++] = x;
}
ans = 0;
dfs(0, 0);
printf("%d\n", ans);
}
return 0;
}
第三題 時間計算, 模擬
#include <cstdio>
int main() {
int t;
scanf("%d", &t);
while(t--) {
int H, M, h, m, s, d;
scanf("%d %d %d %d %d %d", &H, &M, &h, &m, &s, &d);
H = H*60+M;
h = h*60+m;
H = h-H;
if(H%60) H = H/60+1;
else H = H/60;
printf("%d\n", H*d*s);
}
return 0;
}
第四題 前序運算式, 建造一棵運算樹 (其實我忘記他的學術名稱), 總之只有葉節點是值, 非葉節點都是運算子(+-*/), 接著藉由樹的走訪可以輸出跟計算答案
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string.h>
using namespace std;
typedef struct {
int l, r;
int num;
int flag;
} Node;
Node Nd[1000];
int size;
stringstream sin;
void build(int idx) {
string tmp;
sin >> tmp;
if(tmp[0] > '9' || tmp[0] < '0' &&) {
Nd[idx].num = tmp[0];
Nd[idx].flag = 0;
size++;
Nd[idx].l = size;
build(size);
size++;
Nd[idx].r = size;
build(size);
} else {
stringstream nin;
nin << tmp;
int v;
nin >> v;
Nd[idx].num = v;
Nd[idx].flag = 1;
}
}
void travel(int idx) {
if(!Nd[idx].flag) {
if(!Nd[Nd[idx].l].flag)
printf("(");
travel(Nd[idx].l);
if(!Nd[Nd[idx].l].flag)
printf(")");
if(Nd[idx].num == '+') {
printf("+");
} else
if(Nd[idx].num == '*') {
printf("*");
} else
if(Nd[idx].num == '/') {
printf("/");
} else {
printf("-");
}
if(!Nd[Nd[idx].r].flag)
printf("(");
travel(Nd[idx].r);
if(!Nd[Nd[idx].r].flag)
printf(")");
} else {
printf("%d", Nd[idx].num);
}
}
double calu(int idx) {
if(Nd[idx].flag)
return Nd[idx].num;
if(Nd[idx].num == '+') {
return calu(Nd[idx].l)+calu(Nd[idx].r);
} else
if(Nd[idx].num == '*') {
return calu(Nd[idx].l)*calu(Nd[idx].r);
} else
if(Nd[idx].num == '/') {
return calu(Nd[idx].l)/calu(Nd[idx].r);
} else {
return calu(Nd[idx].l)-calu(Nd[idx].r);
}
}
int main() {
int t;
scanf("%d", &t);
getchar();
string line;
while(t--) {
getline(cin, line);
memset(Nd, 0, sizeof(Nd));
sin.clear();
sin << line;
size = 1;
build(1);
travel(1);
printf("=%.2lf\n", calu(1));
}
return 0;
}
第五題 這次最難的題目, 樹形 DP
兩次 dfs
1st dfs :
得到由下而上的最大高度 (要記錄第一高 第二高),
意即 得到每個節點的 subtree 的高度
2nd dfs :
將父節點高度轉過來, 這時要注意, 如果第一高是從這個節點接上去的, 那麼就抓第二高+1
#include <stdio.h>
#include <algorithm>
#include <vector>
#define oo 0xfffffff
using namespace std;
vector<int> edge[95005];
int dp_down[95005][2], dp_up[95005];
int used[95005];
void dfs(int nd) {
for(vector<int>::iterator i = edge[nd].begin(); i != edge[nd].end(); i++) {
if(used[*i] == 0) {
used[*i] = 1;
dfs(*i);
if(dp_down[*i][0]+1 > dp_down[nd][1])
dp_down[nd][1] = dp_down[*i][0]+1;
if(dp_down[nd][1] > dp_down[nd][0])
swap(dp_down[nd][0], dp_down[nd][1]);
}
}
}
void dfs2(int nd, int v) {
dp_up[nd] = v;
for(vector<int>::iterator i = edge[nd].begin(); i != edge[nd].end(); i++) {
if(used[*i] == 0) {
used[*i] = 1;
int hv;
if(dp_down[*i][0]+1 != dp_down[nd][0])
hv = dp_down[nd][0];
else
hv = dp_down[nd][1];
hv = max(hv, dp_up[nd]);
dfs2(*i, hv+1);
}
}
}
int main() {
int n, m, i, y;
while(scanf("%d", &n) == 1) {
for(i = 1; i <= n; i++) {
edge[i].clear();
dp_down[i][0] = 0;
dp_down[i][1] = 0;
dp_up[i] = 0;
used[i] = 0;
}
int x, y;
for(i = 1; i < n; i++) {
scanf("%d %d", &x, &y);
x++, y++;
edge[x].push_back(y);
edge[y].push_back(x);
}
used[1] = 1;
dfs(1);
for(i = 1; i <= n; i++) used[i] = 0;
used[1] = 1;
dfs2(1, 0);
int root[95001], best = oo;
for(i = 1; i <= n; i++) {
root[i] = max(max(dp_down[i][0], dp_down[i][1]), dp_up[i]);
best = min(best, root[i]);
}
for(i = 1; i <= n; i++)
if(root[i] == best) {
printf("%d\n", i-1);
break;
}
}
return 0;
}