回答編集履歴
6
コード整理
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 **r
|
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", r
|
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 r
|
73
|
+
int hasCross = 0; //false
|
53
74
|
int hasClosed = 0; //false
|
54
75
|
|
55
|
-
//最期の辺(r
|
76
|
+
//最期の辺(roads[c-1])の接続先を追う
|
56
|
-
|
77
|
+
int *used = allocAndClear(sizeof(int) * (c-1), 0); //roads に index で対応するフラグ
|
57
|
-
PC *q =
|
78
|
+
PC *q = allocAndClear(sizeof(PC) * n, 0); //点の探索キュー&探索履歴・接続カウント
|
58
79
|
|
59
80
|
int wi = 0, ri = 0;
|
60
|
-
q
|
81
|
+
setPc(q, wi++, roads[c-1]->u, 1); //最後に追加した辺の両端を追加
|
61
|
-
q[wi++].c = 1;
|
62
|
-
q
|
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 に繋がっている辺を
|
85
|
+
for(int i=0; i<c-1; i++) { //点 pc に繋がっている未使用辺を探し、 pc の逆側の点を (q に無ければ )q に追加
|
68
|
-
if(
|
86
|
+
if(used[i] || !isConnected(roads[i], pc->p)) continue;
|
87
|
+
|
88
|
+
used[i] = 1; //true
|
69
|
-
|
89
|
+
hasCross |= countAndCrossCheck(pc);
|
70
|
-
|
71
|
-
int np =
|
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
|
-
|
94
|
+
if(q[j].p == np) { //探索済みor探索予定の点に繋がる?
|
78
95
|
found = 1; //true
|
79
|
-
|
96
|
+
hasCross |= countAndCrossCheck(&q[j]);
|
80
97
|
}
|
81
98
|
}
|
82
|
-
if(!found) {
|
83
|
-
|
99
|
+
hasClosed |= found;
|
84
|
-
|
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(
|
111
|
+
free(used);
|
104
112
|
free(q);
|
105
113
|
|
106
|
-
|
114
|
+
if(hasCross || (hasClosed && c < n)) return DISCARD;
|
107
|
-
|
115
|
+
if(hasClosed && c == n) return COMPLETE;
|
108
|
-
#endif //CHECK_LOG
|
109
|
-
return
|
116
|
+
return CONTINUE;
|
110
117
|
}
|
111
118
|
|
112
119
|
//greedy法
|
113
|
-
|
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
|
125
|
+
case COMPLETE: return result;
|
118
126
|
case DISCARD: c--;
|
119
127
|
}
|
120
128
|
}
|
129
|
+
free(result);
|
121
|
-
return
|
130
|
+
return NULL;
|
122
131
|
}
|
123
132
|
|
124
133
|
//表示
|
125
|
-
void print(int
|
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<
|
140
|
+
for(int j=0, k; j<n; j++) {
|
132
|
-
p =
|
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 ||
|
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
|
-
|
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
|
-
|
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
|
-
|
175
|
+
|
189
|
-
|
190
|
-
|
176
|
+
Adjacent **result = greedy(n, m, adjacents);
|
191
|
-
|
192
|
-
if(
|
177
|
+
if(result) {
|
193
|
-
print(
|
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
|
-
r
|
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
|
-
r
|
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
|
-
r
|
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
|
-
r
|
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
|
-
r
|
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
|
-
r
|
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
|
-
r
|
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
|
-
r
|
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
|
-
r
|
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
|
-
r
|
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
コード修正
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
|
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
|
-
|
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
|
74
|
+
int found = 0; //false
|
35
|
-
for(int j=0; j<c; j++) if(result[j]->u == i || result[j]->v == i) count ++;
|
36
|
-
|
75
|
+
for(int j=0; j<wi; j++) { //過去の点に戻った?
|
37
|
-
|
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
|
-
|
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) r
|
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
|
-
|
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
コード修正
test
CHANGED
@@ -55,7 +55,7 @@
|
|
55
55
|
|
56
56
|
//表示
|
57
57
|
void print(int c, Adjacent **result) {
|
58
|
-
printf("Final Path: ");
|
58
|
+
printf("Final Path: ");
|
59
59
|
double total = 0;
|
60
60
|
int i = 0;
|
61
61
|
int p = result[i]->u;
|
3
コード修正: check 関数の戻り値を追加
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
|
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
|
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
|
40
|
+
if(c == n) return open ? DISCARD : COMPLETE; //辺が足りたなら閉じていなければならない
|
36
|
-
return
|
41
|
+
return DISCARD; //辺が多くなったなら破棄
|
37
42
|
}
|
38
43
|
|
39
44
|
//greedy法
|
40
|
-
|
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
|
-
|
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(
|
96
|
+
printf("Failure\n");
|
97
|
+
}
|
86
98
|
|
87
99
|
return 0;
|
88
100
|
}
|
2
追加
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
説明修正
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
|
|