爬格子呀9.17(图论)

Posted romalzhih

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了爬格子呀9.17(图论)相关的知识,希望对你有一定的参考价值。

刘汝佳的紫书差不多就告一段落吧,我觉得可以了,怎么说呢,这书也陪着自己走了一年多了吧,也目睹了从一个啥也不会的萌新到一个稍微会一点的萌新的转变。

差不多开始下本书吧,自己也大三了,时间真的有点紧啊woctm

最喜欢的图论作为自己对这本书的谢幕,也好,也好


 

uva10735(欧拉回路+网络流)

题意:给一个图,图中有部分是向边,部分是无向边,要求判断是否存在欧拉回路,若存在,输出路径

解法:

技术分享图片

  1 #include<bits/stdc++.h>
  2 #define REP(i, a, b) for(int i = (a); i < (b); i++)
  3 #define MEM(a,x) memset(a,x,sizeof(a)) 
  4 #define INF 0x3f3f3f3f 
  5 #define MAXN 10000+10
  6 using namespace std;
  7 
  8 struct Euler
  9 {
 10     struct Edge {
 11         int to, nxt;
 12         Edge() {}
 13         Edge(int x, int y) :to(x), nxt(y) {}
 14     }edges[MAXN];
 15     int head[MAXN], n, E;
 16     void init(const int &n) {
 17         this->n = n; E = 0;
 18         for (int i = 0; i <= n; i++)head[i] = -1;
 19     }
 20     void AddEdge(int f, int t) {
 21         edges[++E] = Edge(t, head[f]);
 22         head[f] = E;
 23     }
 24     stack<int >S;
 25     bool vis[MAXN];//use when dfs
 26     void dfs(int x) {//get EulerCircle
 27         Edge e;
 28         for (int i = head[x]; i != -1; i = e.nxt) {
 29             e = edges[i];
 30             if (vis[i])continue;
 31             vis[i] = 1;
 32             dfs(e.to);
 33             S.push(x);
 34         }
 35     }
 36     void getEulerCircle() {
 37         while (!S.empty())S.pop();
 38         memset(vis, 0, sizeof(vis));
 39         dfs(1);
 40         for (; !S.empty(); S.pop()) {
 41             printf("%d ", S.top());
 42         }
 43         puts("1");
 44     }
 45 }gg;
 46 
 47 struct Dinic
 48 {
 49     struct Edge {
 50         int from, to, cap, flow;
 51         Edge(int u, int v, int c, int f) :
 52             from(u), to(v), cap(c), flow(f) {}
 53     };
 54     int n, s, t;
 55     vector<Edge>edges;
 56     vector< int>G[MAXN]; //gragh
 57     bool vis[MAXN]; //use when bfs
 58     int d[MAXN], cur[MAXN];//dist,now edge,use in dfs
 59     void AddEdge(int from, int to, int cap) {
 60         edges.push_back(Edge(from, to, cap, 0));
 61         edges.push_back(Edge(to, from, 0, 0));
 62         int top = edges.size();
 63         G[from].push_back(top - 2);
 64         G[to].push_back(top - 1);
 65     }
 66     void init(int n, int s, int t) {
 67         this->n = n;
 68         this->s = s;
 69         this->t = t;
 70         edges.clear();
 71         for (int i = 0; i <= n; i++)G[i].clear();
 72     }
 73 
 74     bool BFS() {
 75         memset(vis, 0, sizeof(vis));
 76         queue<int>Q;
 77         Q.push(s); d[s] = 0; vis[s] = 1;
 78         while (!Q.empty()) {
 79             int x = Q.front(); Q.pop();
 80             for (int i = 0; i < G[x].size(); i++) {
 81                 Edge &e = edges[G[x][i]];
 82                 if (vis[e.to] || e.cap <= e.flow)continue;
 83                 vis[e.to] = 1;
 84                 d[e.to] = d[x] + 1;
 85                 Q.push(e.to);
 86             }
 87         }
 88         return vis[t];
 89     }
 90     int DFS(const int& x, int a) {
 91         if (x == t || a == 0) { return a; }
 92         int flow = 0, f;
 93         for (int& i = cur[x]; i < G[x].size(); i++) {
 94             Edge& e = edges[G[x][i]];
 95             if (d[x] + 1 != d[e.to])continue;
 96             if ((f = DFS(e.to, min(a, e.cap - e.flow))) <= 0)continue;
 97             e.flow += f;
 98             edges[G[x][i] ^ 1].flow -= f;//??
 99             flow += f; a -= f;
100             if (!a) break;
101         }
102         return flow;
103     }
104     int MaxFlow(int s, int t) {
105         int flow = 0;
106         for (; BFS();) {
107             memset(cur, 0, sizeof(cur));
108             flow += DFS(s, INF);
109         }
110         return flow;
111     }
112     void buildEuler(int n) {
113         for (int i = 1; i <= n; i++) {
114             for (int j = 0; j < G[i].size(); j++) {
115                 Edge &e = edges[G[i][j]];
116                 if (e.to == s || e.to == t) continue;
117                 if (!e.cap)continue;
118                 if (e.flow == e.cap)gg.AddEdge(e.to, e.from);
119                 else gg.AddEdge(e.from, e.to);
120             }
121         }
122     }
123 }g;
124 
125 int d[MAXN];//degree = out - in
126 bool work(int n) {
127     int flow = 0;
128     REP(i, 1, n + 1) {
129         if (d[i] & 1)return 0;
130         if (d[i] > 0) {
131             g.AddEdge(g.s, i, d[i] >> 1);
132             flow += d[i] >> 1;
133         }
134         else if (d[i] < 0)
135             g.AddEdge(i, g.t, -(d[i] >> 1));
136     }
137     if (flow != g.MaxFlow(0, n + 1)) return 0;
138     return 1;
139 }
140 
141 int main() {
142     int T, x, y, n, m;
143     scanf("%d", &T);
144     for (char ch; T--;) {
145         scanf("%d%d", &n, &m);
146         g.init(n, 0, n + 1);
147         gg.init(n);
148         MEM(d, 0);
149         REP(i, 0, m) {
150             scanf("%d %d %c", &x, &y, &ch);
151             if (ch == D) gg.AddEdge(x, y);
152             else g.AddEdge(x, y, 1);
153             d[x]++; d[y]--;//Degree
154         }
155         if (!work(n))puts("No euler circuit exist");
156         else {
157             g.buildEuler(n);
158             gg.getEulerCircle();
159         }
160         if (T)puts("");
161     }
162     return 0;
163 }

uva1001

题意:

给出一些球,球内的时间为零,球之间的速度为10每单位。给两个点,求最短时间。

解法:

处理出任意两点之间的距离 && 做题的时候要大胆点hhh

 1 #include<bits/stdc++.h>
 2 #define REP(i, a, b) for(int i = (a); i < (b); i++)
 3 #define MEM(a,x) memset(a,x,sizeof(a)) 
 4 #define INF 0x3f3f3f3f 
 5 #define MAXN 100+10
 6 using namespace std;
 7 struct node { int x, y, z, r; }p[MAXN];
 8 double g[MAXN][MAXN];
 9 
10 double dis(node a,node b) {
11     double ans = sqrt(
12           (a.x - b.x)*(a.x - b.x)
13         + (a.y - b.y)*(a.y - b.y)
14         + (a.z - b.z)*(a.z - b.z))
15         - (a.r + b.r);
16     return ans < 0 ? 0 : ans;
17 }
18 
19 int main() {
20     int n, cnt = 0;
21     while (cin >> n && n != -1) {
22         REP(i, 0, n) cin >> p[i].x >> p[i].y >> p[i].z >> p[i].r;
23         cin >> p[n].x >> p[n].y >> p[n].z; p[n].r = 0;
24         cin >> p[n + 1].x >> p[n + 1].y >> p[n + 1].z; p[n + 1].r = 0;
25 
26         MEM(g, INF);
27         REP(i, 0, n + 2)g[i][i] = 0;
28         REP(i, 0, n + 2)REP(j, 0, n + 2) g[i][j] = dis(p[i], p[j]);
29 
30         REP(k, 0, n + 2)REP(i, 0, n + 2)REP(j, 0, n + 2)
31             g[i][j] = min(g[i][j], g[i][k] + g[k][j]);
32         
33         g[n][n + 1] *= 10;
34         printf("Cheese %d: Travel time = %.0f sec
", ++cnt, g[n][n + 1]);
35     }
36     return 0;
37 }

uva820

题意:有一个计算机网络,输入节点数n,输入网络流源点和汇点src,des,再输入双向边数m。给出m条边的负载,求最大流。

解法:

网络流模板题

你想,流量其实就是运输物品,我们要求的就是从源点到汇点最多能运输多少单位的物品,

当物品变成水流的时候,他可以均匀的分布在所有边上,每个边上可以有的物品数就是这个边的容量,所有可行边的路径和就是我们要求的所谓“路径权值和”

这道题Dinic中的init有问题,改了一下就好了

 1 #include<bits/stdc++.h>
 2 #define REP(i, a, b) for(int i = (a); i < (b); i++)
 3 #define MEM(a,x) memset(a,x,sizeof(a)) 
 4 #define INF 0x3f3f3f3f 
 5 #define MAXN 1000+10
 6 using namespace std;
 7 struct Edge {
 8     int from, to, cap, flow;
 9 };
10 struct Dinic {
11     int n, m, s, t;
12     vector<Edge>edges;
13     vector<int>G[MAXN];
14     bool vis[MAXN];
15     int d[MAXN];
16     int cur[MAXN];
17     void init() {
18         edges.clear();
19         for (int i = 0; i < MAXN; i++) G[i].clear();
20         memset(d, 0, sizeof d);
21     }
22     void AddEdge(int from, int to, int cap) {
23         edges.push_back({ from, to, cap, 0 });
24         edges.push_back({ to, from, 0, 0 });
25         m = edges.size();
26         G[from].push_back(m - 2);
27         G[to].push_back(m - 1);
28     }
29     bool BFS() {
30         int x, i;
31         memset(vis, 0, sizeof(vis));
32         queue<int>Q;
33         Q.push(s);
34         d[s] = 0;
35         vis[s] = 1;
36         while (!Q.empty()) {
37             x = Q.front(), Q.pop();
38             for (i = 0; i < G[x].size(); i++) {
39                 Edge & e = edges[G[x][i]];
40                 if (!vis[e.to] && e.cap > e.flow) {
41                     vis[e.to] = 1;
42                     d[e.to] = d[x] + 1;
43                     Q.push(e.to);
44                 }
45             }
46         }
47         return vis[t];
48     }
49     int DFS(int x, int a) {
50         if (x == t || a == 0)
51             return a;
52         int flow = 0, f;
53         for (int &i = cur[x]; i < G[x].size(); i++) {
54             Edge & e = edges[G[x][i]];
55             if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) {
56                 e.flow += f;
57                 edges[G[x][i] ^ 1].flow -= f;
58                 flow += f;
59                 a -= f;
60                 if (a == 0)
61                     break;
62             }
63         }
64         return flow;
65     }
66     int Maxflow(int s, int t) {
67         this->s = s, this->t = t;
68         int flow = 0;
69         while (BFS()) {
70             memset(cur, 0, sizeof(cur));
71             flow += DFS(s, INF);
72         }
73         return flow;
74     }
75 }Men;
76 int main() {
77     int n, kase = 0;
78     while (scanf("%d", &n) && n) {
79         int s, t, c, u, v, w;
80         Men.init();
81         scanf("%d%d%d", &s, &t, &c);
82         REP(i, 0, c) {
83             scanf("%d%d%d", &u, &v, &w);
84             Men.AddEdge(u, v, w);
85             Men.AddEdge(v, u, w);
86         }
87         printf("Network %d
The bandwidth is %d.

", ++kase, Men.Maxflow(s, t));
88     }
89     return 0;
90 }

uva10801

题意:

一个人在大楼的0楼,大楼最多到99层。有n部电梯,每部电梯有可到达的楼层,每个电梯移动一层的时间为T[i]秒。换电梯的时间为60秒。

给你一个楼层,问你电梯到这个楼层的最短路径。

解法:

很容易看出是一个最短路问题,关键在于如何建图,

首先我们分析一下我们很容易想到把楼层当作点把时间当左边,但是有一个问题由于它涉及楼层中换电梯所以这样做的话我们就无法计算换电梯的时间,所以我的方法是把一个楼层拆成n个点(这样做的前提是在这道题中n比较小<=5)分别表示从哪一个电梯下来的。然后再把相同楼层的点之间加一条长度为60的边。

这样再通过执行n次Dijkstra算法去最小值得出答案。(或者直接Floyd)

 1 #include<bits/stdc++.h>
 2 #define REP(i, a, b) for(int i = (a); i < (b); i++)
 3 #define MEM(a,x) memset(a,x,sizeof(a)) 
 4 #define INF 0x3f3f3f3f 
 5 #define MAXN 100+10
 6 using namespace std;
 7 int t[MAXN], num[MAXN];
 8 int g[MAXN][MAXN];
 9 
10 void AddEdge(int i, int j, int s) {
11     g[i][j] = g[j][i] = min(min(g[i][j], g[j][i]), abs(i - j)*s);
12     return;
13 }
14 
15 int main() {
16     int n, k;
17     while (scanf("%d%d", &n, &k) != EOF) {
18         MEM(g, INF);
19         REP(i, 0, n)scanf("%d", &t[i]);
20         int UP = -1;
21         REP(i, 0, n) {
22             char ch = ;
23             for (int j = 0; ch != 
; j++) {
24                 scanf("%d%c", &num[j], &ch);
25                 UP = max(UP, num[j]);
26                 REP(k, 0, j) AddEdge(num[j], num[k], t[i]);
27             }
28         }
29 
30         UP++;
31         REP(i, 0, UP)g[i][i] = 0;
32         REP(k, 0, UP)REP(i, 0, UP)REP(j, 0, UP)
33             g[i][j] = min(g[i][j], g[i][k] + g[k][j] + 60);
34 
35         if (k == 0)printf("0
");
36         else if (g[0][k] == INF)printf("IMPOSSIBLE
");
37         else printf("%d
", g[0][k]);
38     }
39     return 0;
40 }

uva1663

题意:

给出一些01串,含星号的串表示包含两个串,星号位置分别为0和1。 
每次可以消掉一个串或者两个只有一个数字不同的串,求最少几次可以消掉所有串。 

解法:

读出所有串,两两判断能否一起消掉,然后其最大匹配数即可。具体细节见代码。

这道题的建图挺有意思的

 1 #include<bits/stdc++.h>
 2 #define REP(i, a, b) for(int i = (a); i < (b); i++)
 3 #define CLR(a) memset(a,0,sizeof(a));
 4 #define MEM(a,x) memset(a,x,sizeof(a)) 
 5 #define ALL(x) begin(x),end(x)
 6 #define INF 0x3f3f3f3f 
 7 #define MAXN 2000+10
 8 #define LL long long
 9 using namespace std;
10 
11 int Set[MAXN], n, m;
12 char s[20];
13 
14 int g[MAXN][MAXN], match[MAXN], vis[MAXN];
15 bool dfs(int u) {
16     for (int i = 0; i < MAXN; i++) {
17         if (g[u][i] && !vis[i]) {
18             vis[i] = 1;
19             if (match[i] == -1 || dfs(match[i])) {
20                 match[i] = u;
21                 return true;
22             }
23         }
24     }
25     return false;
26 }
27 
28 int Hungarian(){
29     int ans = 0;
30     memset(match, -1, sizeof(match));
31     for (int i = 0; i < MAXN; i++){
32         memset(vis, 0, sizeof(vis));
33         if (dfs(i))ans++;
34     }
35     return ans;
36 }
37 
38 int main() {
39     while (scanf("%d%d", &n, &m) && (n+m)) {
40         CLR(g); CLR(Set); CLR(vis);
41         REP(i, 0, m) {
42             scanf("%s", s);
43             int pos = -1, tmp = 0;
44             REP(j, 0, n) {
45                 if (s[j] == 1)tmp |= 1 << j;
46                 else if (s[j] == *)pos = j;
47             }
48             Set[tmp] = 1;
49             if (pos != -1) {//将*拆分成0和1两种
50                 tmp |= 1 << pos;
51                 Set[tmp] = true;
52             }
53         }
54         m = 0;
55         REP(i, 0, MAXN) {
56             if (Set[i]) {
57                 m++;
58                 REP(j, 0, n) {
59                     int tmp = i ^ (1 << j);//只有一位不同
60                     if (Set[tmp])g[i][tmp] = true;
61                 }
62             }
63         }
64         printf("%d
", m - Hungarian() / 2);
65     }
66     return 0;
67 }

uva12549

题意:

在一个Y行X列的网格里有空地(.),重要位置(*)和障碍物(#),用最少的机器人看守所有重要位置,每个机器人要放在一个格子里,面朝上下左右4个方向之一。

机器人会发出激光,一直射到障碍物为止,沿途都是看守范围。

解法:

首先肯定是二分图最大匹配;其次如果没有障碍物的话,直接每个目标的x和y建表跑匈牙利即可;

但这个题目中他有障碍物,我们就横纵坐标分块即可(相当于离散化),之后匈牙利

 1 #include<bits/stdc++.h>
 2 #define REP(i, a, b) for(int i = (a); i < (b); i++)
 3 #define CLR(a) memset(a,0,sizeof(a));
 4 #define MEM(a,x) memset(a,x,sizeof(a)) 
 5 #define ALL(x) begin(x),end(x)
 6 #define INF 0x3f3f3f3f 
 7 #define MAXN 100+10
 8 #define MAXM 2005
 9 #define LL long long
10 using namespace std;
11   
12 int g[MAXM][MAXM], match[MAXM], vis[MAXM];
13 int mp[MAXN][MAXN], X[MAXN][MAXN], Y[MAXN][MAXN];
14 int xcnt, ycnt;
15 bool dfs(int u) {
16     for (int i = 0; i < ycnt; i++) {
17         if (g[u][i] && !vis[i]) {
18             vis[i] = 1;
19             if (match[i] == -1 || dfs(match[i])) {
20                 match[i] = u;
21                 return true;
22             }
23         }
24     }
25     return false;
26 }
27 
28 int Hungarian() {
29     int ans = 0;
30     memset(match, -1, sizeof(match));
31     for (int i = 0; i < xcnt; i++) {
32         memset(vis, 0, sizeof(vis));
33         if (dfs(i))ans++;
34     }
35     return ans;
36 }
37 
38 int main() {
39     int T; scanf("%d", &T);
40     while (T--) {
41         CLR(g); CLR(mp); CLR(X); CLR(Y);
42         getchar();
43         int n, m; scanf("%d%d", &n, &m);
44 
45         int p, x, y;
46         scanf("%d", &p);
47         REP(i, 0, p) { scanf("%d %d", &x, &y); mp[x-1][y-1] = 1; }
48         scanf("%d", &p);
49         REP(i, 0, p) { scanf("%d %d", &x, &y); mp[x-1][y-1] = 2; }
50 
51         xcnt = -1;
52         REP(i, 0, n) {
53             bool flag = true;
54             REP(j, 0, m) {
55                 if (mp[i][j] == 1) {
56                     if (flag)xcnt++;
57                     X[i][j] = xcnt;
58                     flag = false;
59                 }
60                 else if(mp[i][j]==2)
61                     flag = true;
62             }
63         }
64         ycnt = -1;
65         REP(i, 0, n) {
66             bool flag = true;
67             REP(j, 0, m) {
68                 if (mp[j][i] == 1) {
69                     if (flag)ycnt++;
70                     Y[j][i] = ycnt;
71                     flag = false;
72                 }
73                 else if (mp[j][i] == 2)
74                     flag = true;
75             }
76         }
77         xcnt++, ycnt++;
78 
79         REP(i, 0, n)REP(j, 0, m)if(mp[i][j]==1)
80             g[X[i][j]][Y[i][j]] = 1;
81         printf("%d
", Hungarian());
82     }
83     return 0;
84 }

uva1664

题意:

给你n个点,接着给你n-1条边形成一颗生成树,每条边都有一个权值。

求的是以一个点作为特殊点,并求出从此点出发到其他每个点的条件边权的总和最大,条件边权就是:起点到终点经过的权值的最小值。

解法:

非常巧妙的并查集;真的没有想到;

首先我们把要选的那个结点看作是我们的根节点,用Kruscal的思想,首先给所有边按照从大到小的顺序排序,

之后我们遍历每条边,该边的两个顶点所在的集合设为A、B,集合A、B的顶点a、b,要让谁当中心点呢?

易知:无论谁当中心点,它与另一个集合中任一点的容量都为该边长度(因为是从大到小枚举的)。

那么为了求出总容量,我们要维护一些值,用空间换时间 。

维护每个顶点的总容量sum[i],维护每个顶点与之相连的顶点数量,cnt[i],当前答案ans 。

那么对于a、b点,如果以a为中心,总容量为sum[a] + cnt[b] * e[i].c 。

反之亦然,哪个量大,则以哪个点为城市中心,也就是并查集的根结点 。

 1 #include<bits/stdc++.h>
 2 #define REP(i, a, b) for(int i = (a); i < (b); i++)
 3 #define CLR(a) memset(a,0,sizeof(a));
 4 #define MEM(a,x) memset(a,x,sizeof(a)) 
 5 #define ALL(x) begin(x),end(x)
 6 #define LL long long
 7 const int INF = 0x3f3f3f3f;
 8 const int MAXN = 200000 + 10;
 9 using namespace std;
10 
11 struct edge {
12     int u, v, w;
13     bool operator < (const edge& rhs) const {
14         return w > rhs.w;
15     }
16 }e[MAXN];
17 LL p[MAXN], sum[MAXN], cnt[MAXN];
18 int findSet(int x) { return p[x] == x ? x : p[x] = findSet(p[x]); }
19 int main() {
20     int n;
21     while (scanf("%d", &n) != EOF) {
22         REP(i, 0, n - 1) {scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);}
23         REP(i, 1, n+1) {p[i] = i; sum[i] = 0; cnt[i] = 1;}
24         sort(e, e + n - 1);
25         LL ans = 0;
26         REP(i, 0, n - 1) {
27             int x = findSet(e[i].u), y = findSet(e[i].v);
28             LL sumu = sum[x] + cnt[y] * e[i].w;
29             LL sumv = sum[y] + cnt[x] * e[i].w;
30             if (sumu < sumv) {
31                 p[x] = y; cnt[y] += cnt[x];
32                 ans = sum[y] = sumv;
33             }
34             else {
35                 p[y] = x; cnt[x] += cnt[y]; sum[x] = sumu;
36                 ans = sum[x] = sumu;
37             }
38         }
39         printf("%lld
", ans);
40     }
41     return 0;
42 }

uva1668(建图)

题意:

给定一棵有 nn 个节点的树,每条边有边权 w(u,v)w(u,v),用最小的路径覆盖所有的边,使得每条边被覆盖的次数等于其边权。

解法:

这道题考的是思维。

首先我们求出所有点的权值之和,就是我们要求的答案的最大值;再求出每个点的最大权值,依次看其是否超过总权值的一半;

如果超过的话,我们就直接减去最大权值,代表不能全部合并; 否则,我们就减去总权值的一半,代表能全部合并;

 1 #include<bits/stdc++.h>
 2 #define REP(i, a, b) for(int i = (a); i < (b); i++)
 3 #define CLR(a) memset(a,0,sizeof(a));
 4 #define MEM(a,x) memset(a,x,sizeof(a)) 
 5 #define ALL(x) begin(x),end(x)
 6 #define LL long long
 7 #define INF 0x3f3f3f3f
 8 #define MAXN 100000 + 10
 9 using namespace std;
10 
11 int deg[MAXN], maxd[MAXN];
12 int  main() {
13     int T; scanf("%d", &T);
14     int kase = 0;
15     while (T--) {
16         CLR(deg); CLR(maxd);
17         int n; scanf("%d", &n);
18         int u, v, w;
19         LL ans = 0;
20         REP(i, 1, n) {
21             scanf("%d%d%d", &u, &v, &w);
22             deg[u] += w, deg[v] += w;
23             maxd[u] = max(maxd[u], w);
24             maxd[v] = max(maxd[v], w);
25             ans += w;
26         }
27         REP(i, 1, n+1) {
28             if ((maxd[i] << 1) <= deg[i])
29                 ans -= deg[i] >> 1;
30             else 
31                 ans -= deg[i] - maxd[i];
32         }
33         printf("Case #%d: %lld
", ++kase, ans);
34     }
35     return 0;
36 }

 


以上是关于爬格子呀9.17(图论)的主要内容,如果未能解决你的问题,请参考以下文章

[图论][最短路]步行

图论算法与模型(训练指南题库)

图论.DP

图论刷题-1剑指 Offer 13. 机器人的运动范围

图论刷题-1剑指 Offer 13. 机器人的运动范围

9.17homework