题目链接:2010 ACM-ICPC Multi-University Training Contest(1)——Host by FZU

昨天superbin把这套题拿出来做练习,5个小时过去了,杯具就这样发生了,一道都没过!

比赛后,看了wzc大牛的解题报告,刷了三道

hdu3433: A Task Process

DP + 二分枚举

k表示第i个工人完成k件甲任务,(T - Aik) / Bi 表示剩余的时间用来完成的乙任务数。

平时dp学的太龊了,改了好久才完成。dp的时候对dp数组的初始化是个很关键的问题,有时候即使转移方程写出来了,也不一定能AC,这一题,可以将不可能完成的任务都赋成-1,dp数组初始化为-1.

代码
1 #include<stdio.h>
2 #include<string.h>
3  #define NN 52
4  #define XX 202
5 #define INF 1 << 30
6
7 int X, N, Y;
8 int dp[NN][XX];
9 int cost[NN][2];
10 int Min(int a, int b){
11 return a < b ? a : b;
12 }
13
14 int Max(int a, int b){
15 return a > b ? a : b;
16 }
17
18 int Dp(int T){
19 int i, j, k, t;
20
21 for(i = 0; i <= N; i++){ // 数组初始化
22 for (j = 0; j <= X; j++){
23 dp[i][j] = -1;
24 }
25 }
26
27 for (i = 0; i <= X; i++){
28 t = T - i * cost[1][0];
29 if (t < 0)
30 dp[1][i] = -1; // 如果剩余的时间小于0,表示不可能完成,这里开始置成0了
31 else dp[1][i] = t / cost[1][1];
32 }
33
34 for (i = 2; i <= N; i++){
35 for (j = 0; j <= X; j++){
36 for (k = 0; k <= j; k++){
37 if (dp[i - 1][k] < 0) break; // 如果不可能,当k更大的时候就更不可能了
38 if (T - (j - k) * cost[i][0] >= 0) // 剩余时间的得保证非负
39 dp[i][j] = Max(dp[i][j], dp[i - 1][k] + (T - (j - k) * cost[i][0]) / cost[i][1]);
40 }
41 }
42 }
43 return dp[N][X] >= Y;
44 }
45 int main()
46 {
47 int T, mina, minb, mid, low, hig, ans, maxT, i;
48 int it = 1;
49 scanf("%d", &T);
50 while(T--){
51 scanf("%d%d%d", &N, &X, &Y);
52 mina = minb = INF;
53 for (i = 1; i <= N; i++){
54 scanf("%d%d", &cost[i][0], &cost[i][1]);
55 mina = Min(mina, cost[i][0]);
56 minb = Min(minb, cost[i][1]);
57 }
58 maxT = mina * X + minb * Y; // 取一个时间上限
59 low = 0;
60 hig = maxT;
61 ans = hig;
62 do{// 二分时间,来判断是否可行,枚举到最短时间
63 mid = (low + hig) >> 1;
64 if (Dp(mid)){
65 ans = mid;
66 hig = mid - 1;
67 }else{
68 low = mid + 1;
69 }
70 }while(low <= hig);
71 printf("Case %d: %d\n", it++, ans);
72 }
73 return 0;
74 }
75

跑的比较慢,不过还是过了,应该还有更好的方法吧。

hdu3440: House Man

差分约束系统 + SPFA

比较简单,不过比赛的时候一直WA,没想到这题居然卡INF,ans的最大值为10^9,我开始定义INF 为0xffffff,正好差了一点,就杯具了。

1 typedef struct node1{
2 int h, id;
3 }NODE1;
4 NODE1 f[NN];

h为高度,id为house左右次序编号

S为最矮的house的编号,T为最高的house的编号

按高度排序。一共有两种边:
1. 位置相邻的两个house间距 >= 1,<id, id - 1, -1>(2=< id <= N)

2. 高度相邻的两个house间距 <= 4,<min(f[i-1].id, f[i].id), max(f[i-1].id, f[i].id), D>(2 <= i <= N)

处理的时候令dis[S < T ? S : T] = 0

输出的结果是dis[S < T ? T : S]

 

代码
1 #include<stdio.h>
2 #include<stdlib.h>
3 #include<string.h>
4 #define NN 1004
5 #define MM 2004
6 #define INF 0x3fffffff // 开始的时候定义小了,杯具
7 typedef struct node1{
8 int h, id;
9 }NODE1;
10 NODE1 f[NN];
11 typedef struct node{
12 int v, wt;
13 struct node *nxt;
14 }NODE;
15
16 NODE edg[MM];
17 NODE *link[NN];
18
19 int idx, N, S, T, D;
20 int dis[NN];
21 int stack[NN];
22 int mark[NN];
23 int cnt[NN];
24
25 int cmp(const void *a, const void *b){
26 NODE1 *aa = (NODE1 *)a;
27 NODE1 *bb = (NODE1 *)b;
28
29 return aa->h - bb->h;
30 }
31
32 void Add(int a, int b, int c){ // 加边
33 idx++;
34 edg[idx].v = b;
35 edg[idx].wt = c;
36 edg[idx].nxt = link[a];
37 link[a] = edg + idx;
38 }
39
40 int Spfa(){
41 int u, v, i;
42 int top = 0;
43 memset(mark, 0, sizeof(mark));
44
45 for (i = 1; i <= N; i++){
46 dis[i] = INF;
47 }
48 for (i = 1; i <= N; i++){ // 将所有点入栈,就不用建源点和所有点相连了
49 stack[++top] = i;
50 cnt[i] = 1;
51 mark[i] = 1;
52 }
53 if (S < T) // 将标号小的置为0
54 dis[S] = 0;
55 else dis[T] = 0;
56
57 while(top){
58 u = stack[top--];
59 mark[u] = 0;
60 for (NODE *p = link[u]; p; p = p->nxt){
61 v = p->v;
62 if (dis[v] > dis[u] + p->wt){
63 dis[v] = dis[u] + p->wt;
64 if (!mark[v]){
65 stack[++top] = v;
66 cnt[v]++;
67 mark[v] = 1;
68 if (cnt[v] > N + 2) return -1; // 当某一点入栈次数超过N(N 为节点数),表示有负环,我这里用了N + 2
69 }
70 }
71 }
72 }
73 if (S < T) // 输出标号大的
74 return dis[T];
75 else return dis[S];
76 }
77 void Solve(){
78 int i;
79 idx = 0;
80 memset(link, 0, sizeof(link));
81 for (i = 2; i <= N; i++){
82 Add(i, i - 1, -1);
83 }
84
85 qsort(f + 1, N, sizeof(f[0]), cmp);
86 S = f[1].id;
87 T = f[N].id;
88 for (i = 2; i <= N; i++){
89 if (f[i - 1].id < f[i].id){ // 标号小的到标号大的建边,边权为D
90 Add(f[i - 1].id, f[i].id, D);
91 }else{
92 Add(f[i].id, f[i - 1].id, D);
93 }
94 }
95 printf("%d\n", Spfa());
96 }
97 int main()
98 {
99 int Tt, it, i;
100 scanf("%d", &Tt);
101 for(it = 1; it <= Tt; it++){
102 scanf("%d%d", &N, &D);
103 for (i = 1; i <= N; i++){
104 scanf("%d", &f[i].h);
105 f[i].id = i;
106 }
107 printf("Case %d: ", it);
108 Solve();
109 }
110 return 0;
111 }
112

hdu3442 Three Kingdoms

BFS + 优先队列

开始看到这道题的时候感觉需要处理的太多,“果断”放弃,后来发现这题其实是最水的一道。

比赛的时候优先队列忘了,这是最大的杯具,基础不牢啊!

向队友学习 探索之美——接触优先队列

这题没什么好说的,易错的地方见代码。

代码
1 #include<stdio.h>
2 #include<string.h>
3 #include<queue>
4 #include<iostream>
5 using namespace std;
6 #define INF 0xfffffff
7 struct node{
8 int x, y, c;
9 char vis[6];
10 bool operator < (const node &a) const{
11 return a.c < c;
12 }
13 }sta, end;
14
15 int r, c;
16 int hurt[100]; // 保存每个字符的伤害值
17 int map0[52][52][100]; // map0[x][y][ch] 表示位置[x, y]会受到字符ch类攻击
18 char map[52][52];
19 char mark[52][52];
20 int dir[4][2] = {0, 1, 1, 0, 0, -1, -1, 0};
21
22 int judge(int x, int y, char vis[]){// 判断走到点[x, y]要受到的伤害值
23 int i, ans;
24 ans = 0;
25 for (i = 'A'; i <= 'E'; i++){
26 if (map0[x][y][i] == 1 && !vis[i - 'A']){ // 如果已经收到此类过伤害,就不管了,否则,加上
27 vis[i - 'A'] = 1;
28 ans += hurt[i];
29 }
30 }
31 return ans;
32 }
33 int bfs(){
34 int i;
35 struct node cur, nxt;
36 priority_queue<struct node> pq;
37 pq.push(sta);
38 mark[sta.x][sta.y] = 1;
39 while(!pq.empty()){
40 cur = pq.top();
41 if (map[cur.x][cur.y] == '!') return cur.c; // 如果在最少的伤害值时找到了出口,即可return
42 pq.pop();
43 for (i = 0; i < 4; i++){
44 nxt.x = cur.x + dir[i][0];
45 nxt.y = cur.y + dir[i][1];
46 memcpy(nxt.vis, cur.vis, sizeof(cur.vis)); // 每个状态的受到的伤害情况也要传给后继节点,刚开始我就这地方错了
47 if (nxt.x >= 0 && nxt.x < r && nxt.y >= 0 && nxt.y < c){
48 if (!mark[nxt.x][nxt.y]){// 一共就三个位置可以走,'C', '!', '.'
49 if (map[nxt.x][nxt.y] == 'C'){
50 mark[nxt.x][nxt.y] = 1;
51 nxt.c = cur.c + judge(nxt.x, nxt.y, nxt.vis);
52 pq.push(nxt);
53 }else if (map[nxt.x][nxt.y] == '!'){// 这里不要标记,得到的可能不是最优的,不过这题数据好像可以在这里直接return
54 nxt.c = cur.c + judge(nxt.x, nxt.y, nxt.vis);
55 pq.push(nxt);
56 }
57 else if (map[nxt.x][nxt.y] == '.'){
58 mark[nxt.x][nxt.y] = 1;
59 nxt.c = cur.c + judge(nxt.x, nxt.y, nxt.vis);
60 pq.push(nxt);
61 }
62 }
63 }
64 }
65 }
66 return -1;
67 }
68
69 void dfs1(int x, int y, int step, char ch){// 查找攻击范围
70 int i, cx, cy;
71 if (x < 0 || x >= r || y < 0 || y >= c) return;
72 map0[x][y][ch] = 1;
73 if (step <= 0) return; // 开始把这个语句放到上面的句子前面了,少考虑了好多点
74 for (i = 0; i < 4; i++){
75 cx = x + dir[i][0];
76 cy = y + dir[i][1];
77 dfs1(cx, cy, step - 1, ch);
78 }
79 }
80
81 int main(){
82 int T, i, j, it;
83 hurt['A'] = 1;
84 hurt['B'] = 2;
85 hurt['C'] = 3;
86 hurt['D'] = 4;
87 hurt['E'] = 5;
88 scanf("%d", &T);
89 for(it = 1; it <= T; it++){
90 scanf("%d%d", &r, &c);
91 for (i = 0; i < r; i++){
92 scanf("%s", map[i]);
93 }
94 memset(map0, 0, sizeof(map0));
95 for (i = 0; i < r; i++){
96 for (j = 0; j < c; j++){
97 if (map[i][j] == '$'){
98 sta.x = i; sta.y = j;
99 sta.c = 0;
100 }else if (map[i][j] == '!'){
101 end.x = i; end.y = j;
102 }else if (map[i][j] == 'A'){ // A有2步的攻击范围,用一个dfs来找到这些点并标记,B, C, D, E也一样
103 dfs1(i, j, 2, 'A');
104 }else if (map[i][j] == 'B'){
105 dfs1(i, j, 3, 'B');
106 }else if (map[i][j] == 'C'){
107 map0[i][j]['C'] = 1;
108 }else if (map[i][j] == 'D'){
109 dfs1(i, j, 2, 'D');
110 }else if (map[i][j] == 'E'){
111 dfs1(i, j, 1, 'E');
112 }
113 }
114 }
115 for (i = 0; i <= 5; i++){ // 初始化
116 sta.vis[i] = 0;
117 }
118
119 memset(mark, 0, sizeof(mark));
120 printf("Case %d: %d\n", it, bfs());
121 }
122 return 0;
123 }
124

 

posted on 2010-08-09 16:12  ylfdrib  阅读(1210)  评论(0编辑  收藏  举报