回答編集履歴

6

コード整理

2023/07/26 09:20

投稿

jimbe
jimbe

スコア13318

test CHANGED
@@ -22,8 +22,9 @@
22
22
  #include <stdio.h>
23
23
  #include <stdlib.h>
24
24
  #include <string.h>
25
-
25
+ #include <assert.h>
26
+
26
- //#define TEST
27
+ //#define CHECK_TEST
27
28
  #define CHECK_LOG
28
29
 
29
30
  typedef struct {
@@ -32,143 +33,129 @@
32
33
  double dist; //点間の距離
33
34
  } Adjacent;
34
35
 
36
+ int isConnected(Adjacent *a, int p) {
37
+ return p == a->u || p == a->v;
38
+ }
39
+ int otherPoint(Adjacent *a, int p) {
40
+ return p == a->u ? a->v : a->u;
41
+ }
42
+
35
43
  typedef struct {
36
44
  int p, c;
37
45
  } PC;
46
+
47
+ void setPc(PC *pc, int i, int p, int c) {
48
+ pc[i].p = p;
49
+ pc[i].c = c;
50
+ }
51
+ int countAndCrossCheck(PC *pc) {
52
+ return ++pc->c > 2;
53
+ }
54
+
55
+ //size バイトのメモリを確保し、各バイトに value をセット
56
+ void *allocAndClear(size_t size, int value) {
57
+ return memset(malloc(size), value, size);
58
+ }
38
59
 
39
60
  //判定
40
61
  #define DISCARD (-1) //(最期に追加した辺を)破棄
41
62
  #define CONTINUE (0) //継続
42
63
  #define COMPLETE (1) //完了
43
64
 
44
- int check(int n, int c, Adjacent **result) {
65
+ int check(int n, int c, Adjacent **roads) {
45
66
  #ifdef CHECK_LOG
46
67
  printf("n=%d,c=%d\n", n, c);
47
- for(int i=0; i<c; i++) printf("%d-%d\n", result[i]->u, result[i]->v);
68
+ for(int i=0; i<c; i++) printf("%d-%d\n", roads[i]->u, roads[i]->v);
48
69
  #endif //CHECK_LOG
49
70
 
50
71
  if(c > n) return DISCARD; //辺が多くなったなら破棄
51
72
 
52
- int rinf = CONTINUE;
73
+ int hasCross = 0; //false
53
74
  int hasClosed = 0; //false
54
75
 
55
- //最期の辺(result[c-1])の接続先を追う
76
+ //最期の辺(roads[c-1])の接続先を追う
56
- Adjacent **cpy = memcpy(malloc(sizeof(Adjacent*) * c), result, sizeof(Adjacent*) * c);
77
+ int *used = allocAndClear(sizeof(int) * (c-1), 0); //roads index で対応するフラグ
57
- PC *q = memset(malloc(sizeof(PC) * n), 0, sizeof(PC) * n);
78
+ PC *q = allocAndClear(sizeof(PC) * n, 0); //点の探索キュー&探索履歴・接続カウント
58
79
 
59
80
  int wi = 0, ri = 0;
60
- q[wi].p = cpy[c-1]->u; //最後に追加した辺の両端を追加
81
+ setPc(q, wi++, roads[c-1]->u, 1); //最後に追加した辺の両端を追加
61
- q[wi++].c = 1;
62
- q[wi].p = cpy[c-1]->v;
82
+ setPc(q, wi++, roads[c-1]->v, 1);
63
- q[wi++].c = 1;
64
- cpy[c-1] = NULL;
65
83
  while(ri < wi) {
66
84
  PC *pc = &q[ri++];
67
- for(int i=0; i<c-1; i++) { //点 p に繋がっている辺を cpy から探し、 p の逆側の点を q に追加、辺を cpy から削除
85
+ for(int i=0; i<c-1; i++) { //点 pc に繋がっている未使用辺を探し、 pc の逆側の点を (q に無ければ )q に追加
68
- if(cpy[i] == NULL || (cpy[i]->u != pc->p && cpy[i]->v != pc->p)) continue;
86
+ if(used[i] || !isConnected(roads[i], pc->p)) continue;
87
+
88
+ used[i] = 1; //true
69
- if(++pc->c > 2) rinf = DISCARD;
89
+ hasCross |= countAndCrossCheck(pc);
70
-
71
- int np = pc->p == cpy[i]->u ? cpy[i]->v : cpy[i]->u; //p の逆側の点
90
+ int np = otherPoint(roads[i], pc->p); //p の逆側の点
72
- cpy[i] = NULL;
73
91
 
74
92
  int found = 0; //false
75
- for(int j=0; j<wi; j++) { //過去の点に戻った?
93
+ for(int j=0; j<wi; j++) {
76
- if(q[j].p == np) {
77
- hasClosed = 1; //true
94
+ if(q[j].p == np) { //探索済みor探索予定の点に繋がる?
78
95
  found = 1; //true
79
- if(++q[j].c > 2) rinf = DISCARD;
96
+ hasCross |= countAndCrossCheck(&q[j]);
80
97
  }
81
98
  }
82
- if(!found) {
83
- q[wi].p = np;
99
+ hasClosed |= found;
84
- q[wi++].c = 1;
100
+ if(!found) setPc(q, wi++, np, 1);
85
- }
86
101
  }
87
102
  }
88
103
 
89
104
  #ifdef CHECK_LOG
90
105
  printf("wi=%d\n", wi);
91
106
  for(int i=0; i<wi; i++) printf("p=%d,c=%d\n", q[i].p, q[i].c);
107
+ printf("hasCross=%d, hasClosed=%d\n", hasCross, hasClosed);
108
+ printf("\n");
92
109
  #endif //CHECK_LOG
93
110
 
94
- if(hasClosed) {
95
- rinf = DISCARD;
96
- if(wi == n) {
97
- int count = 0;
98
- for(int i=0; i<wi; i++) if(q[i].c == 2) count ++;
99
- if(count == n) rinf = COMPLETE; //点全部が 2 辺と接続した閉路なら COMPLETE
100
- }
101
- }
102
-
103
- free(cpy);
111
+ free(used);
104
112
  free(q);
105
113
 
106
- #ifdef CHECK_LOG
114
+ if(hasCross || (hasClosed && c < n)) return DISCARD;
107
- printf("rinf=%d\n", rinf);
115
+ if(hasClosed && c == n) return COMPLETE;
108
- #endif //CHECK_LOG
109
- return rinf;
116
+ return CONTINUE;
110
117
  }
111
118
 
112
119
  //greedy法
113
- int greedy(int n, int m, Adjacent *adjacent, Adjacent **result) {
120
+ Adjacent **greedy(int n, int m, Adjacent *adjacent) {
121
+ Adjacent **result = malloc(sizeof(Adjacent*) * n);
114
122
  for(int i=0, c=0; i<m; i++) {
115
123
  result[c++] = &adjacent[i];
116
124
  switch(check(n, c, result)) {
117
- case COMPLETE: return c;
125
+ case COMPLETE: return result;
118
126
  case DISCARD: c--;
119
127
  }
120
128
  }
129
+ free(result);
121
- return 0;
130
+ return NULL;
122
131
  }
123
132
 
124
133
  //表示
125
- void print(int c, Adjacent **result) {
134
+ void print(int n, Adjacent **result) {
126
135
  printf("Final Path: ");
127
136
  double total = 0;
128
137
  int i = 0;
129
138
  int p = result[i]->u;
130
139
  printf("%d", p);
131
- for(int j=0, k; j<c; j++) {
140
+ for(int j=0, k; j<n; j++) {
132
- p = p == result[i]->u ? result[i]->v : result[i]->u;
141
+ p = otherPoint(result[i], p);
133
142
  printf(" -> %d", p);
134
143
  total += result[i]->dist;
135
- for(k=i, i=0; i==k || (result[i]->u != p && result[i]->v != p); i++); //次の i
144
+ for(k=i, i=0; i==k || !isConnected(result[i], p); i++); //次の i
136
145
  }
137
146
  printf("\n");
138
147
  printf("Total Distance: %.1lf\n", total);
139
148
  }
140
149
 
141
150
  int main(void) {
142
- #ifdef TEST
151
+ #ifdef CHECK_TEST
143
- printf("TEST start\n");
144
- Adjacent testdata1[] = {
152
+ Adjacent testdata1[] = { {0,1,100}, {2,3,110}, {3,4,120}, {2,4,130} };
145
- {0,1,100},
146
- {2,3,110},
147
- {3,4,120},
148
- {2,4,130},
149
- };
150
- Adjacent *test1[] = {
153
+ Adjacent *test1[] = { &testdata1[0], &testdata1[1], &testdata1[2], &testdata1[3] };
151
- &testdata1[0],
152
- &testdata1[1],
153
- &testdata1[2],
154
- &testdata1[3],
155
- };
156
- if(check(5, 4, test1) != DISCARD) printf("%d error\n", __LINE__);
154
+ assert(check(5, 4, test1) == DISCARD);
157
-
155
+
158
- Adjacent testdata2[4] = {
156
+ Adjacent testdata2[4] = { {0,2,100}, {2,3,110}, {3,4,120}, {1,4,130} };
159
- {0,2,100},
160
- {2,3,110},
161
- {3,4,120},
162
- {1,4,130},
163
- };
164
- Adjacent *test2[] = {
157
+ Adjacent *test2[] = { &testdata2[0], &testdata2[1], &testdata2[2], &testdata2[3] };
165
- &testdata2[0],
166
- &testdata2[1],
167
- &testdata2[2],
168
- &testdata2[3],
169
- };
170
- if(check(5, 4, test2) != CONTINUE) printf("%d error\n", __LINE__);
158
+ assert(check(5, 4, test2) == CONTINUE);
171
- printf("end\n");
172
159
  #else //TEST
173
160
  //ファイル読み込み・ソート等を省略
174
161
  int n = 5; //点の数
@@ -185,12 +172,11 @@
185
172
  {0,4, 1055.9},
186
173
  {2,4, 1592.3},
187
174
  };
188
- Adjacent *result[10] = {0}; //結果保存領域(adjacents の要素へのポインタ)
175
+
189
-
190
- int c = greedy(n, m, adjacents, result);
176
+ Adjacent **result = greedy(n, m, adjacents);
191
-
192
- if(c == n) {
177
+ if(result) {
193
- print(c, result); //最終的な経路を表示
178
+ print(n, result); //最終的な経路を表示
179
+ free(result);
194
180
  } else {
195
181
  printf("Failure\n");
196
182
  }
@@ -204,7 +190,8 @@
204
190
  wi=2
205
191
  p=1,c=1
206
192
  p=3,c=1
207
- rinf=0
193
+ hasCross=0, hasClosed=0
194
+
208
195
  n=5,c=2
209
196
  1-3
210
197
  0-3
@@ -212,7 +199,8 @@
212
199
  p=0,c=1
213
200
  p=3,c=2
214
201
  p=1,c=1
215
- rinf=0
202
+ hasCross=0, hasClosed=0
203
+
216
204
  n=5,c=3
217
205
  1-3
218
206
  0-3
@@ -221,7 +209,8 @@
221
209
  p=0,c=2
222
210
  p=1,c=2
223
211
  p=3,c=2
224
- rinf=-1
212
+ hasCross=0, hasClosed=1
213
+
225
214
  n=5,c=3
226
215
  1-3
227
216
  0-3
@@ -231,7 +220,8 @@
231
220
  p=4,c=1
232
221
  p=3,c=2
233
222
  p=0,c=1
234
- rinf=0
223
+ hasCross=0, hasClosed=0
224
+
235
225
  n=5,c=4
236
226
  1-3
237
227
  0-3
@@ -243,7 +233,8 @@
243
233
  p=3,c=2
244
234
  p=1,c=2
245
235
  p=4,c=1
246
- rinf=0
236
+ hasCross=0, hasClosed=0
237
+
247
238
  n=5,c=5
248
239
  1-3
249
240
  0-3
@@ -256,7 +247,8 @@
256
247
  p=0,c=2
257
248
  p=1,c=2
258
249
  p=4,c=1
259
- rinf=-1
250
+ hasCross=1, hasClosed=1
251
+
260
252
  n=5,c=5
261
253
  1-3
262
254
  0-3
@@ -269,7 +261,8 @@
269
261
  p=1,c=2
270
262
  p=0,c=2
271
263
  p=2,c=1
272
- rinf=-1
264
+ hasCross=1, hasClosed=1
265
+
273
266
  n=5,c=5
274
267
  1-3
275
268
  0-3
@@ -282,7 +275,8 @@
282
275
  p=3,c=2
283
276
  p=4,c=1
284
277
  p=0,c=2
285
- rinf=-1
278
+ hasCross=1, hasClosed=1
279
+
286
280
  n=5,c=5
287
281
  1-3
288
282
  0-3
@@ -295,7 +289,8 @@
295
289
  p=3,c=2
296
290
  p=2,c=1
297
291
  p=1,c=2
298
- rinf=-1
292
+ hasCross=1, hasClosed=1
293
+
299
294
  n=5,c=5
300
295
  1-3
301
296
  0-3
@@ -308,7 +303,8 @@
308
303
  p=0,c=2
309
304
  p=1,c=2
310
305
  p=3,c=2
311
- rinf=1
306
+ hasCross=0, hasClosed=1
307
+
312
308
  Final Path: 1 -> 3 -> 0 -> 2 -> 4 -> 1
313
309
  Total Distance: 3311.1
314
310
  ```

5

コード修正

2023/07/25 17:06

投稿

jimbe
jimbe

スコア13318

test CHANGED
@@ -1,22 +1,30 @@
1
1
  valid 関数は、最後に追加した辺を用いるかどうかを返します。
2
- 最後に追加した辺を用いるかどうかは、以下の点で判断出来ます。
2
+ ~~最後に追加した辺を用いるかどうかは、以下の点で判断出来ます。~~
3
-
3
+
4
- 1. 辺の数が全ての点を回るのに不足している場合:閉路が出来たら false, 出来なかったなら true
4
+ ~~1. 辺の数が全ての点を回るのに不足している場合:閉路が出来たら false, 出来なかったなら true
5
5
  2. 辺の数が全ての点を回るのに必要な数に達した場合:完全な閉路が出来たら true, 出来なかったら false
6
- 3. 辺の数が多くなった場合:false
6
+ 3. 辺の数が多くなった場合:false~~
7
-
7
+
8
- 1 と 2 で閉路の扱いが逆ですので、判断もそのようにする必要があると思います。
8
+ ~~1 と 2 で閉路の扱いが逆ですので、判断もそのようにする必要があると思います。~~
9
-
9
+
10
- 閉路の判定は、(実際に辿ってみなくても)各点から出る辺の数によって判断出来るのではないでしょうか。
10
+ ~~閉路の判定は、(実際に辿ってみなくても)各点から出る辺の数によって判断出来るのではないでしょうか。
11
11
  点から1本だけ辺が出ていれば、開いている部分があります。
12
12
  点から3本以上辺が出ていれば、完全な閉路は出来なくなりますし、一部が閉路になった可能性があります。
13
13
  全ての点から2本の辺が出ていれば、完全な閉路が出来たということでしょう。
14
14
  これらの条件の組み合わせを考えれば判断出来るものと思います。
15
- **※ざっくり考えたものですので穴がある可能性があります。**
15
+ ※ざっくり考えたものですので穴がある可能性があります。~~
16
16
 
17
17
  valid 関数を check に名前を変えて、戻り値を DISCARD/CONTINUE/COMPLETE の 3 つとして状況を返すようにしました。
18
+
19
+ 間違いを指摘頂きまして、結局最後に追加された辺から辿ることになりました。
20
+ 間違ったコードのままよりは良いかなと・・・**これが間違っていないとは言い切れません**が。
18
21
  ```c
19
22
  #include <stdio.h>
23
+ #include <stdlib.h>
24
+ #include <string.h>
25
+
26
+ //#define TEST
27
+ #define CHECK_LOG
20
28
 
21
29
  typedef struct {
22
30
  int u; //点1
@@ -24,21 +32,81 @@
24
32
  double dist; //点間の距離
25
33
  } Adjacent;
26
34
 
35
+ typedef struct {
36
+ int p, c;
37
+ } PC;
38
+
27
39
  //判定
28
40
  #define DISCARD (-1) //(最期に追加した辺を)破棄
29
41
  #define CONTINUE (0) //継続
30
42
  #define COMPLETE (1) //完了
43
+
31
44
  int check(int n, int c, Adjacent **result) {
45
+ #ifdef CHECK_LOG
46
+ printf("n=%d,c=%d\n", n, c);
47
+ for(int i=0; i<c; i++) printf("%d-%d\n", result[i]->u, result[i]->v);
48
+ #endif //CHECK_LOG
49
+
50
+ if(c > n) return DISCARD; //辺が多くなったなら破棄
51
+
52
+ int rinf = CONTINUE;
53
+ int hasClosed = 0; //false
54
+
55
+ //最期の辺(result[c-1])の接続先を追う
56
+ Adjacent **cpy = memcpy(malloc(sizeof(Adjacent*) * c), result, sizeof(Adjacent*) * c);
57
+ PC *q = memset(malloc(sizeof(PC) * n), 0, sizeof(PC) * n);
58
+
32
- int open = 0;
59
+ int wi = 0, ri = 0;
60
+ q[wi].p = cpy[c-1]->u; //最後に追加した辺の両端を追加
61
+ q[wi++].c = 1;
62
+ q[wi].p = cpy[c-1]->v;
63
+ q[wi++].c = 1;
64
+ cpy[c-1] = NULL;
33
- for(int i=0; i<n; i++) {
65
+ while(ri < wi) {
66
+ PC *pc = &q[ri++];
67
+ for(int i=0; i<c-1; i++) { //点 p に繋がっている辺を cpy から探し、 p の逆側の点を q に追加、辺を cpy から削除
68
+ if(cpy[i] == NULL || (cpy[i]->u != pc->p && cpy[i]->v != pc->p)) continue;
69
+ if(++pc->c > 2) rinf = DISCARD;
70
+
71
+ int np = pc->p == cpy[i]->u ? cpy[i]->v : cpy[i]->u; //p の逆側の点
72
+ cpy[i] = NULL;
73
+
34
- int count = 0; //点i が現れる数
74
+ int found = 0; //false
35
- for(int j=0; j<c; j++) if(result[j]->u == i || result[j]->v == i) count ++;
36
- if(count > 2) return DISCARD; // 1 つの点から 3 本以上辺が出ているなら破棄
75
+ for(int j=0; j<wi; j++) { //過去の点に戻った?
37
- open |= count == 1;
76
+ if(q[j].p == np) {
77
+ hasClosed = 1; //true
78
+ found = 1; //true
79
+ if(++q[j].c > 2) rinf = DISCARD;
38
- }
80
+ }
81
+ }
82
+ if(!found) {
83
+ q[wi].p = np;
84
+ q[wi++].c = 1;
85
+ }
86
+ }
87
+ }
88
+
89
+ #ifdef CHECK_LOG
90
+ printf("wi=%d\n", wi);
39
- if(c < n) return open ? CONTINUE : DISCARD; //辺がまだ足りないなら開いていなければならない
91
+ for(int i=0; i<wi; i++) printf("p=%d,c=%d\n", q[i].p, q[i].c);
92
+ #endif //CHECK_LOG
93
+
94
+ if(hasClosed) {
95
+ rinf = DISCARD;
96
+ if(wi == n) {
97
+ int count = 0;
98
+ for(int i=0; i<wi; i++) if(q[i].c == 2) count ++;
40
- if(c == n) return open ? DISCARD : COMPLETE; //辺が足りならじていければなない
99
+ if(count == n) rinf = COMPLETE; //点全部が 2 と接続した閉なら COMPLETE
100
+ }
101
+ }
102
+
103
+ free(cpy);
104
+ free(q);
105
+
106
+ #ifdef CHECK_LOG
107
+ printf("rinf=%d\n", rinf);
41
- return DISCARD; //辺が多くなったなら破棄
108
+ #endif //CHECK_LOG
109
+ return rinf;
42
110
  }
43
111
 
44
112
  //greedy法
@@ -71,6 +139,37 @@
71
139
  }
72
140
 
73
141
  int main(void) {
142
+ #ifdef TEST
143
+ printf("TEST start\n");
144
+ Adjacent testdata1[] = {
145
+ {0,1,100},
146
+ {2,3,110},
147
+ {3,4,120},
148
+ {2,4,130},
149
+ };
150
+ Adjacent *test1[] = {
151
+ &testdata1[0],
152
+ &testdata1[1],
153
+ &testdata1[2],
154
+ &testdata1[3],
155
+ };
156
+ if(check(5, 4, test1) != DISCARD) printf("%d error\n", __LINE__);
157
+
158
+ Adjacent testdata2[4] = {
159
+ {0,2,100},
160
+ {2,3,110},
161
+ {3,4,120},
162
+ {1,4,130},
163
+ };
164
+ Adjacent *test2[] = {
165
+ &testdata2[0],
166
+ &testdata2[1],
167
+ &testdata2[2],
168
+ &testdata2[3],
169
+ };
170
+ if(check(5, 4, test2) != CONTINUE) printf("%d error\n", __LINE__);
171
+ printf("end\n");
172
+ #else //TEST
74
173
  //ファイル読み込み・ソート等を省略
75
174
  int n = 5; //点の数
76
175
  int m = 10; //辺の数
@@ -95,11 +194,121 @@
95
194
  } else {
96
195
  printf("Failure\n");
97
196
  }
98
-
197
+ #endif //TEST
99
198
  return 0;
100
199
  }
101
200
  ```
102
201
  ```
202
+ n=5,c=1
203
+ 1-3
204
+ wi=2
205
+ p=1,c=1
206
+ p=3,c=1
207
+ rinf=0
208
+ n=5,c=2
209
+ 1-3
210
+ 0-3
211
+ wi=3
212
+ p=0,c=1
213
+ p=3,c=2
214
+ p=1,c=1
215
+ rinf=0
216
+ n=5,c=3
217
+ 1-3
218
+ 0-3
219
+ 0-1
220
+ wi=3
221
+ p=0,c=2
222
+ p=1,c=2
223
+ p=3,c=2
224
+ rinf=-1
225
+ n=5,c=3
226
+ 1-3
227
+ 0-3
228
+ 1-4
229
+ wi=4
230
+ p=1,c=2
231
+ p=4,c=1
232
+ p=3,c=2
233
+ p=0,c=1
234
+ rinf=0
235
+ n=5,c=4
236
+ 1-3
237
+ 0-3
238
+ 1-4
239
+ 0-2
240
+ wi=5
241
+ p=0,c=2
242
+ p=2,c=1
243
+ p=3,c=2
244
+ p=1,c=2
245
+ p=4,c=1
246
+ rinf=0
247
+ n=5,c=5
248
+ 1-3
249
+ 0-3
250
+ 1-4
251
+ 0-2
252
+ 2-3
253
+ wi=5
254
+ p=2,c=2
255
+ p=3,c=3
256
+ p=0,c=2
257
+ p=1,c=2
258
+ p=4,c=1
259
+ rinf=-1
260
+ n=5,c=5
261
+ 1-3
262
+ 0-3
263
+ 1-4
264
+ 0-2
265
+ 3-4
266
+ wi=5
267
+ p=3,c=3
268
+ p=4,c=2
269
+ p=1,c=2
270
+ p=0,c=2
271
+ p=2,c=1
272
+ rinf=-1
273
+ n=5,c=5
274
+ 1-3
275
+ 0-3
276
+ 1-4
277
+ 0-2
278
+ 1-2
279
+ wi=5
280
+ p=1,c=3
281
+ p=2,c=2
282
+ p=3,c=2
283
+ p=4,c=1
284
+ p=0,c=2
285
+ rinf=-1
286
+ n=5,c=5
287
+ 1-3
288
+ 0-3
289
+ 1-4
290
+ 0-2
291
+ 0-4
292
+ wi=5
293
+ p=0,c=3
294
+ p=4,c=2
295
+ p=3,c=2
296
+ p=2,c=1
297
+ p=1,c=2
298
+ rinf=-1
299
+ n=5,c=5
300
+ 1-3
301
+ 0-3
302
+ 1-4
303
+ 0-2
304
+ 2-4
305
+ wi=5
306
+ p=2,c=2
307
+ p=4,c=2
308
+ p=0,c=2
309
+ p=1,c=2
310
+ p=3,c=2
311
+ rinf=1
103
312
  Final Path: 1 -> 3 -> 0 -> 2 -> 4 -> 1
104
313
  Total Distance: 3311.1
105
314
  ```

4

コード修正

2023/07/23 11:45

投稿

jimbe
jimbe

スコア13318

test CHANGED
@@ -55,7 +55,7 @@
55
55
 
56
56
  //表示
57
57
  void print(int c, Adjacent **result) {
58
- printf("Final Path: "); fflush(stdout);
58
+ printf("Final Path: ");
59
59
  double total = 0;
60
60
  int i = 0;
61
61
  int p = result[i]->u;

3

コード修正: check 関数の戻り値を追加

2023/07/23 11:42

投稿

jimbe
jimbe

スコア13318

test CHANGED
@@ -13,6 +13,8 @@
13
13
  全ての点から2本の辺が出ていれば、完全な閉路が出来たということでしょう。
14
14
  これらの条件の組み合わせを考えれば判断出来るものと思います。
15
15
  **※ざっくり考えたものですので穴がある可能性があります。**
16
+
17
+ valid 関数を check に名前を変えて、戻り値を DISCARD/CONTINUE/COMPLETE の 3 つとして状況を返すようにしました。
16
18
  ```c
17
19
  #include <stdio.h>
18
20
 
@@ -23,25 +25,32 @@
23
25
  } Adjacent;
24
26
 
25
27
  //判定
28
+ #define DISCARD (-1) //(最期に追加した辺を)破棄
29
+ #define CONTINUE (0) //継続
30
+ #define COMPLETE (1) //完了
26
- int is_valid(int n, int c, Adjacent **result) {
31
+ int check(int n, int c, Adjacent **result) {
27
32
  int open = 0;
28
33
  for(int i=0; i<n; i++) {
29
34
  int count = 0; //点i が現れる数
30
35
  for(int j=0; j<c; j++) if(result[j]->u == i || result[j]->v == i) count ++;
31
- if(count > 2) return 0; // 1 つの点から 3 本以上辺が出ているなら false
36
+ if(count > 2) return DISCARD; // 1 つの点から 3 本以上辺が出ているなら破棄
32
37
  open |= count == 1;
33
38
  }
34
- if(c < n) return open; //辺がまだ足りないなら開いていなければならない
39
+ if(c < n) return open ? CONTINUE : DISCARD; //辺がまだ足りないなら開いていなければならない
35
- if(c == n) return !open; //辺が足りたなら閉じていなければならない
40
+ if(c == n) return open ? DISCARD : COMPLETE; //辺が足りたなら閉じていなければならない
36
- return 0; //辺が多くなったなら false
41
+ return DISCARD; //辺が多くなったなら破棄
37
42
  }
38
43
 
39
44
  //greedy法
40
- void greedy(int n, int m, Adjacent *adjacent, Adjacent **result) {
45
+ int greedy(int n, int m, Adjacent *adjacent, Adjacent **result) {
41
46
  for(int i=0, c=0; i<m; i++) {
42
- result[c] = &adjacent[i];
47
+ result[c++] = &adjacent[i];
43
- if(is_valid(n, c+1, result)) c++;
48
+ switch(check(n, c, result)) {
49
+ case COMPLETE: return c;
50
+ case DISCARD: c--;
51
+ }
44
52
  }
53
+ return 0;
45
54
  }
46
55
 
47
56
  //表示
@@ -75,14 +84,17 @@
75
84
  {3,4, 871.2},
76
85
  {1,2, 1015.1},
77
86
  {0,4, 1055.9},
78
- {2,4, 1592.3}
87
+ {2,4, 1592.3},
79
88
  };
80
89
  Adjacent *result[10] = {0}; //結果保存領域(adjacents の要素へのポインタ)
81
90
 
82
- greedy(n, m, adjacents, result);
91
+ int c = greedy(n, m, adjacents, result);
83
92
 
93
+ if(c == n) {
84
- // 最終的な経路を表示
94
+ print(c, result); //最終的な経路を表示
95
+ } else {
85
- print(n, result);
96
+ printf("Failure\n");
97
+ }
86
98
 
87
99
  return 0;
88
100
  }

2

追加

2023/07/23 04:32

投稿

jimbe
jimbe

スコア13318

test CHANGED
@@ -6,6 +6,13 @@
6
6
  3. 辺の数が多くなった場合:false
7
7
 
8
8
  1 と 2 で閉路の扱いが逆ですので、判断もそのようにする必要があると思います。
9
+
10
+ 閉路の判定は、(実際に辿ってみなくても)各点から出る辺の数によって判断出来るのではないでしょうか。
11
+ 点から1本だけ辺が出ていれば、開いている部分があります。
12
+ 点から3本以上辺が出ていれば、完全な閉路は出来なくなりますし、一部が閉路になった可能性があります。
13
+ 全ての点から2本の辺が出ていれば、完全な閉路が出来たということでしょう。
14
+ これらの条件の組み合わせを考えれば判断出来るものと思います。
15
+ **※ざっくり考えたものですので穴がある可能性があります。**
9
16
  ```c
10
17
  #include <stdio.h>
11
18
 

1

説明修正

2023/07/23 03:26

投稿

jimbe
jimbe

スコア13318

test CHANGED
@@ -1,4 +1,11 @@
1
+ valid 関数は、最後に追加した辺を用いるかどうかを返します。
2
+ 最後に追加した辺を用いるかどうかは、以下の点で判断出来ます。
3
+
4
+ 1. 辺の数が全ての点を回るのに不足している場合:閉路が出来たら false, 出来なかったなら true
5
+ 2. 辺の数が全ての点を回るのに必要な数に達した場合:完全な閉路が出来たら true, 出来なかったら false
6
+ 3. 辺の数が多くなった場合:false
7
+
1
- 全て点を回らなうちは閉じないということは数にって閉じているかいないかの判定を逆にする形になると思います。
8
+ 1 と 2 で閉路が逆ですので判断もそのよにする必要があると思います。
2
9
  ```c
3
10
  #include <stdio.h>
4
11