zoukankan      html  css  js  c++  java
  • 图论例题合集(一)

    目录

    A:LightOJ - 1251 Forming the Council

    B:LightOJ - 1063 Ant Hills

    C:LightOJ - 1291 Real Life Traffic

    D:LightOJ - 1074 Extended Traffic

    E:LightOJ - 1108 Instant View of Big Bang

    F:LightOJ - 1221 Travel Company

    G:LightOJ - 1002 Country Roads

    H:LightOJ - 1029 Civil and Evil Engineer


    A:LightOJ - 1251 Forming the Council:题目大意:一共有N个选民,M个参选者,一个选民有两个意向,对于+ 表示希望这个人当选。 - 表示希望这个人落选,至少满足一条的结果,对于这个选民来讲就是满足的。问是否有一个可行解,使得所有选民都满足。如果有,输出当选的人的编号。思路:很明显的2-Sat问题。首先我们将一个参选者的当选和不当选进行拆点。i代表第i个人当选了,i+n代表这个人没有当选。那么这个问题就变成了一个经典的2-Sat问题。

    #include<stdio.h>
    #include<string.h>
    #include<vector>
    #include<queue>
    using namespace std;
    int output[40005];
    int vis[70005];
    int low[70005];
    int dfn[70005];
    int print[70005];
    int stack[70005];
    int color[70005];
    int pos[70005];
    int degree[70005];
    vector<int >mp[70005];
    vector<int >mp2[70005];
    int n,m,sig,cnt,tot,cont;
    void add(int x,int y)
    {
        mp[x].push_back(y);
    }
    void top()
    {
        memset(print,0,sizeof(print));
        queue<int >s;
        for(int i=1;i<=sig;i++)
        {
            if(degree[i]==0)
            {
                s.push(i);
            }
        }
        while(!s.empty())
        {
            int u=s.front();
            if(print[u]==0)
            {
                print[u]=1;print[pos[u]]=2;
            }
            s.pop();
            for(int i=0;i<mp2[u].size();i++)
            {
                int v=mp2[u][i];
                degree[v]--;
                if(degree[v]==0)s.push(v);
            }
        }
        cont=0;
        for(int i=1;i<=n;i++)if(print[color[i]]==1)output[cont++]=i;
    }
    void Tarjan(int u)
    {
        vis[u]=1;
        dfn[u]=low[u]=cnt++;
        stack[++tot]=u;
        for(int i=0;i<mp[u].size();i++)
        {
            int v=mp[u][i];
            if(vis[v]==0)Tarjan(v);
            if(vis[v]==1)low[u]=min(low[u],low[v]);
        }
        if(low[u]==dfn[u])
        {
            sig++;
            do
            {
                vis[stack[tot]]=-1;
                color[stack[tot]]=sig;
            }
            while(stack[tot--]!=u);
        }
    }
    int Slove()
    {
        sig=0;
        cnt=1;
        tot=-1;
        memset(degree,0,sizeof(degree));
        memset(stack,0,sizeof(stack));
        memset(dfn,0,sizeof(dfn));
        memset(low,0,sizeof(low));
        memset(vis,0,sizeof(vis));
        memset(color,0,sizeof(color));
        for(int i=1;i<=n*2;i++)
        {
            if(vis[i]==0)
            {
                Tarjan(i);
            }
        }
        for(int i=1;i<=n;i++)
        {
            if(color[i]==color[i+n])return 0;
            pos[color[i]]=color[i+n];
            pos[color[i+n]]=color[i];
        }
        for(int i=1;i<=n*2;i++)
        {
            for(int j=0;j<mp[i].size();j++)
            {
                int v=mp[i][j];
                if(color[i]!=color[v])
                {
                    degree[color[i]]++;
                    mp2[color[v]].push_back(color[i]);
                }
            }
        }
        top();
        return 1;
    }
    int main()
    {
        int t;
        int kase=0;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d%d",&m,&n);
            for(int i=1;i<=60000;i++)mp[i].clear(),mp2[i].clear();
            for(int i=0;i<m;i++)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                int xx=x;int yy=y;
                if(x<0)x=-x;
                if(y<0)y=-y;
                if(xx>0&&yy>0)add(x+n,y),add(y+n,x);
                if(xx>0&&yy<0)add(x+n,y+n),add(y,x);
                if(xx<0&&yy>0)add(x,y),add(y+n,x+n);
                if(xx<0&&yy<0)add(x,y+n),add(y,x+n);
            }
            int ans=Slove();
            printf("Case %d: ",++kase);
            if(ans==1)
            {
                printf("Yes
    ");
                printf("%d",cont);
                for(int i=0;i<cont;i++)
                {
                    printf(" %d",output[i]);
                }
                printf("
    ");
            }
            else printf("No
    ");
        }
    }

    B:LightOJ - 1063 Ant Hills:题目大意:给你n个点,m条边,然后让你破坏某个点使得至少其他两个点不连通,就是用强连通求割点个数。思路:求割点的模板。

    #include<set>
    #include<stack>
    #include<vector>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define endl '
    '
    using namespace std;
     
    const int maxn = 10010;
     
    vector<int> v[maxn];
    stack<int> s;
    set<int> cut;
    int low[maxn],DFN[maxn],vis[maxn];
    int Belong[maxn];//Belong数组的值是1~scc
    int num[maxn];//各个强连通分量包含点的个数,数组编号1~scc
    int id;
    int scc;//强连通分量的个数
    void Tarjan(int x,int fa)
    {
        low[x]  = DFN[x] = ++id;
        vis[x] = 1;
        s.push(x);
        int son = 0;
        for(int i=0;i<v[x].size();i++)
        {
            int xx = v[x][i];
            if(!DFN[xx])
            {
                Tarjan(xx,x);
                low[x]=min(low[x],low[xx]);
                //求割点
                if (fa == -1 && son != 0)
                    cut.insert(x);
                if (fa != -1 && low[xx] >= DFN[x])
                    cut.insert(x);
                son++;
            }
            else if(vis[xx])
                low[x]=min(low[x],DFN[xx]);
        }
        if(low[x]==DFN[x])
        {
            scc++;
            while(s.size())
            {
                int xx=s.top();
                s.pop();
                num[scc]++;
                Belong[xx] = scc;
                vis[xx] = 0;
                if(xx==x)
                    break;
            }
        }
    }
    void solve(int n)
    {
        for(int i = 1;i <= n;i++)
            if(!DFN[i])
                Tarjan(i,-1);
    }
    void init()
    {
        memset(DFN,0,sizeof(DFN));
        memset(num,0,sizeof(num));
        memset(vis,0,sizeof(vis));
        while(s.size())
            s.pop();
        cut.clear();
        for(int i=0;i<=maxn;i++)
            v[i].clear();
        scc = id = 0;
    }
    int main(void)
    {
        int T,n,m;
        scanf("%d",&T);
        int cas = 1;
        while(T--)
        {
            scanf("%d%d",&n,&m);
            init();
            for(int i=1;i<=m;i++)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                v[x].push_back(y);
                v[y].push_back(x);
            }
            solve(n);
            printf("Case %d: %d
    ",cas++,cut.size());
        }
        return 0;
    }

    C:LightOJ - 1291 Real Life Traffic:题意:最少添加几条边 可以使全图边双连通。思路:简单的缩点问题。通过Tarjian求出各个双连通分支后缩点,统计出树中度为1的节点的个数,即为叶节点的个数,记为leaf。则至少在树上添加(leaf+1)/2条边,就能使树达到边二连通,所以至少添加的边数就是(leaf+1)/2。具体方法为,首先把两个最近公共祖先最远的两个叶节点之间连接一条边,这样可以把这两个点到祖先的路径上所有点收缩到一起,因为一个形成的环一定是双连通的。然后再找两个最近公共祖先最远的两个叶节点,这样一对一对找完,恰好是(leaf+1)/2次,把所有点收缩到了一起。
     

    #include <vector>
    #include <cstdio>
    #include <cstring>
    #include <stack>
    #include <algorithm>
    using namespace std;
    const int maxn = 10010;
    vector <int> a[maxn];
    int pre[maxn];
    int low[maxn];
    int bccno[maxn];
    int dfs_clock;
    int bcc_cnt;
    int bri;
    int n, m;
    int degree[maxn];
    stack <int> S;
    
    void dfs(int u, int fa)
    {
    	low[u] = pre[u] = ++dfs_clock;
    	S.push(u);
    	for (int i = 0; i < a[u].size(); i++)
    	{
    		int v = a[u][i];
    		if (v == fa)
    			continue;
    		if (!pre[v])
    		{
    			dfs(v, u);
    			low[u] = min(low[u], low[v]);
    		}
    		else if (v != fa)
    			low[u] = min(low[u], pre[v]);
    	}
    	if (low[u] == pre[u])
    	{
    		bcc_cnt++;
    		while (1)
    		{
    			int x = S.top(); S.pop();
    			bccno[x] = bcc_cnt;
    			if (x == u)
    				break;
    		}
    	}
    }
    void find_bcc()
    {
    	memset(pre, 0, sizeof(pre));
    	memset(bccno, 0, sizeof(bccno));
    	dfs_clock = bcc_cnt = bri = 0;
    	for (int i = 0; i < n; i++)
    		if (!pre[i])
    			dfs(i, -1);
    }
    int main()
    {
    	int cas = 1;
    	int T;
    	scanf("%d", &T);
    	while (T--)
    	{
    		scanf("%d %d", &n, &m);
    		for (int i = 0; i <= n; i++)
    			a[i].clear();
    		while (m--)
    		{
    			int u, v;
    			scanf("%d %d", &u, &v);
    			a[u].push_back(v);
    			a[v].push_back(u);
    		}
    
    		find_bcc();
    		memset(degree, 0, sizeof(degree));
    		for (int u = 0; u < n; u++)
    		{
    			for (int i = 0; i < a[u].size(); i++)
    			{
    				int v = a[u][i];
    				if (bccno[u] != bccno[v])
    				{
    					degree[bccno[u]]++;
    					degree[bccno[v]]++;
    				}
    			}
    		}
    		int ans = 0;
    		for (int i = 1; i <= bcc_cnt; i++)
    			if (degree[i] == 2)
    				ans++;
    		printf("Case %d: %d
    ", cas++, (ans + 1) / 2);
    	}
    	return 0;
    }

    D:LightOJ - 1074 Extended Traffic:题目大意:就是有n个点,1--n的顺序给出每个点都有一定的拥挤值,然后给你m条边,这m条边表示相连着,着m条边的边权值是目的地点的值减去出发点的值的3次方,注意,这是有向图,然后再给你q个点,去求1号点到这q个点的最小值,如果值小于3,或者不能够到达,那就输出 ‘?’思路:可以用spfa算法判断负环。SPFA就是Bellman 的队列优化,所以每个点最多进入到队列中n次就可以找到最短路,如果是进入到队列里面大于等于n次就说明存在负权回路,在这道题目中,负权回路上的所有的点都是不满足题意的,所以就输出  "?"。

    #include<iostream>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    const int maxn = 205;
    int cnt;
    int t, n, m;
    typedef struct {
    	int nxt, to, w;
    }edge;
    int head[maxn], num[maxn], dis[maxn], cir[maxn];
    edge edges[maxn * 100];
    int v[maxn], vis[maxn];
    void add(int from, int to, int w) {
    	edges[++cnt].to = to;
    	edges[cnt].w = w;
    	edges[cnt].nxt = head[from];
    	head[from] = cnt;
    }
    void dfs(int id) {
    	cir[id] = true;
    	for (int i = head[id]; i; i = edges[i].nxt) {
    		if (!cir[edges[i].to])
    			dfs(edges[i].to);
    	}
    }
    void spfa(int s) {
    	queue<int>st;
    	st.push(s);
    	num[1] = 1; vis[1] = 1; dis[1] = 0;
    	while (!st.empty()) {
    		int cur = st.front(); st.pop();
    		vis[cur] = false;
    		if (cir[cur])continue;
    		for (int i = head[cur]; i; i = edges[i].nxt) {
    			int v = edges[i].to;
    			if (dis[v] > edges[i].w + dis[cur]) {
    				dis[v] = edges[i].w + dis[cur];
    				if (!vis[v]) {
    					st.push(v);
    					vis[v] = true;
    					num[v]++;
    					if (num[v] == n) {
    						dfs(v);
    					}
    				}
    			}
    		}
    	}
    }
    void init() {
    	memset(dis, inf, sizeof(dis));
    	memset(head, 0, sizeof(head));
    	memset(num, 0, sizeof(num));
    	memset(vis, 0, sizeof(vis));
    	memset(cir, 0, sizeof(cir));
    	cnt = 0;
    }
    int main() {
    	cin >> t;
    	int x, y;
    	int qt = 1;
    	while (t--) {
    		init();
    		cin >> n;
    		for (int i = 1; i <= n; i++) {
    			cin >> v[i];
    		}
    		cin >> m;
    		for (int i = 1; i <= m; i++) {
    			cin >> x >> y;
    			add(x, y, ((v[y] - v[x]) * (v[y] - v[x]) * (v[y] - v[x])));
    		}
    		spfa(1);
    		cout << "Case " << qt++ << ":" << endl;
    		int ca, query;
    		cin >> ca;
    		for (int i = 1; i <= ca; i++) {
    			cin >> query;
    			if (dis[query] >= inf || dis[query] < 3 || cir[query]) {
    				cout << "?" << endl;
    			}
    			else {
    				cout << dis[query] << endl;
    			}
    		}
    	}
    }

    E:LightOJ - 1108 Instant View of Big Bang:题意:求哪些点可以回到过去 首先负环的点是可以的 一直在付欢里转即可 然后那些可以走到负环的点满足。思路:反向建图 这样负环还是不会变的 只不过负环的方向换了下 原来能到负环的点变成了现在负环能到的点 求出负环标记然后广搜负环能到的点再标记。

    //注意没说起点,所以spfa中dis数组的初始化全为零并把所有点放到队列里
    #include<iostream>
    #include<cstring>
    #include<queue>
    using namespace std;
    const int inf = 0x3f3f3f3f;
    const int maxn = 2050;
    int cnt;
    int t, n, m;
    typedef struct {
    	int nxt, to, w;
    }edge;
    int head[maxn], num[maxn], dis[maxn], cir[maxn];
    edge edges[maxn * 100];
    int v[maxn], vis[maxn];
    void add(int from, int to, int w) {
    	edges[++cnt].to = to;
    	edges[cnt].w = w;
    	edges[cnt].nxt = head[from];
    	head[from] = cnt;
    }
    void dfs(int id) {
    	cir[id] = true;
    	for (int i = head[id]; i; i = edges[i].nxt) {
    		if (!cir[edges[i].to])
        		dfs(edges[i].to);
    	}
    }
    void spfa(int s) {
    	queue<int>st;
    	st.push(s);
        dis[0] = 0;
    	for (int i = 0; i < n; i++)
    	{
    		dis[i] = 0;
    		st.push(i);
    	}
    	while (!st.empty()) {
    		int cur = st.front(); st.pop();
    		vis[cur] = false;
    		if (cir[cur])continue;
    		for (int i = head[cur]; i; i = edges[i].nxt) {
    			int v = edges[i].to;
    			if (dis[v] > edges[i].w + dis[cur]) {
    				dis[v] = edges[i].w + dis[cur];
    				if (!vis[v]) {
    					st.push(v);
    					vis[v] = true;
    					num[v]++;
    					if (num[v] >= n) {
    						dfs(v);
    					}
    				}
    			}
    		}
    	}
    }
    void init() {
    	memset(dis, 0, sizeof(dis));
    	memset(head, 0, sizeof(head));
    	memset(num, 0, sizeof(num));
    	memset(vis, 0, sizeof(vis));
    	memset(cir, 0, sizeof(cir));
    	cnt = 0;
    }
    int main() {
    	cin >> t;
    	int x, y, z;
    	int qt = 1;
    	while (t--) {
    		init();
    		cin >> n >> m;
    		for (int i = 1; i <= m; i++) {
    			cin >> x >> y >> z;
    			add(y, x, z);
    		}
    		spfa(0);
    		cout << "Case " << qt++ << ":" ;
    		int flag = 0;
    		for (int i = 0; i < n; i++) {
    			if (cir[i]) {
    				cout << ' ' << i;
    				flag = 1;
    			}
    		}
    		
    		if (flag)
    			cout << endl;
    		else
    			cout << " impossible" << endl;
    	}
    }

    F:LightOJ - 1221 Travel Company:题目: 旅游公司推出了一种新的旅游路线,这里有n个城市,编号为0~n-1,有m条路线,每行输入u v in out 4个变量,u v 代表编号为u和v的两个城市相连,in代表旅游公司在这条路线上的收入,out代表支出,最开始一行给出一个利润率p(收入/支出),公司要求找到一条循环路线(即一个环),使得总利率大于p。
    思路: 我们可以根据题意写出这么一条原始的公式:(in[0]+in[1]+...+in[k])/(out[0]+out[1]+...+out[k])>p
    即p*(out[0]+out[1]+...+out[k])<(in[0]+in[1]+....in[k]), 故,就是对于这个环中的任意一条边,都要求p*out[i]-in[i]<0,即在图中存在负环。用Spfa算法,因为最短路最多对边松弛n-1次就可以求出来,那么如果一个点入队次数等于n,说明存在负环,即不存在最短路。

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <cctype>
    #include <cstdlib>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <set>
    #include <map>
    #include <list>
    using namespace std;
    const  int maxn = 50100;
    const int INF = 0x3f3f3f3f;
    int n, m, dis[maxn], vis[maxn], intime[maxn];
    vector < pair<int, int> > eg[maxn];
    int spfa(int src)
    {
    	queue <int> Q;
    	memset(dis, INF, sizeof(dis));
    	memset(vis, 0, sizeof(vis));
    	memset(intime, 0, sizeof(intime));
    	dis[src] = 0;
    	Q.push(src);
    	while (!Q.empty()){
    		int u = Q.front(); Q.pop();
    		vis[u] = 0; intime[u]++;
    		if (intime[u] > n)
    			return 1;
    		int len = eg[u].size();
    		for (int i = 0; i < len; i++){
    			int v = eg[u][i].first;
    			int w = eg[u][i].second;
    			if (dis[v] > dis[u] + w){
    				dis[v] = dis[u] + w;
    				if (!vis[v]){
    					vis[v] = 1;
    					Q.push(v);
    				}
    			}
    		}
    	}
    	return 0;
    }
    int main()
    {
    	int T, p, cas = 1;
    	scanf("%d", &T);
    	while (T--) {
    		scanf("%d%d%d", &n, &m, &p);
    		for (int i = 0; i <= n; i++)
    			eg[i].clear();
    		while (m--){
    			int u, v, in, out;
    			scanf("%d%d%d%d", &u, &v, &in, &out);
    			int tem = out * p - in;
    			eg[u].push_back(make_pair(v, tem));
    		}
    		printf("Case %d: ", cas++);
    		int flag = 1;
    		for (int i = 0; i < n; i++){
    			if (spfa(i)){
    				flag = 0;
    				printf("YES
    ");
    				break;
    			}
    		}
    		if (flag)
    			printf("NO
    ");
    	}
    	return 0;
    }

    G:LightOJ - 1002 Country Roads:题目:一共n个城市 ,m 条路, 最后还有一个城市编号 t, 求从t 城市到所有城市的每一条路径中最长边中最小的那条边, 如果到不了 ,输出"Impossible"。思路:具体描述可看https://blog.csdn.net/qq_44765711/article/details/100526905

    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <cctype>
    #include <cstdlib>
    #include <algorithm>
    #include <vector>
    #include <queue>
    #include <stack>
    #include <set>
    #include <map>
    #include <list>
    using namespace std;
    const  int maxn = 50100;
    const int INF = 0x3f3f3f3f;
    int n, m, x, dis[maxn], vis[maxn], intime[maxn];
    vector < pair<int, int> > eg[maxn];
    void spfa(int src)
    {
    	queue <int> Q;
    	memset(dis, INF, sizeof(dis));
    	memset(vis, 0, sizeof(vis));
    	dis[src] = 0;
    	Q.push(src);
    	while (!Q.empty()){
    		int u = Q.front(); Q.pop();
    		vis[u] = 0;
    		int len = eg[u].size();
    		for (int i = 0; i < len; i++){
    			int v = eg[u][i].first;
    			int w = eg[u][i].second;
    			int tmp = max(dis[u], w);
    			if (dis[v] >  tmp){
    				dis[v] =  tmp;
    				if (!vis[v]){
    					vis[v] = 1;
    					Q.push(v);
    				}
    			}
    		}
    	}
    }
    int main()
    {
    	int T, cas = 1;
    	scanf("%d", &T);
    	while (T--) {
    		scanf("%d%d", &n, &m);
    		for (int i = 0; i <= n; i++)
    			eg[i].clear();
    		while (m--){
    			int u, v, w;
    			scanf("%d%d%d", &u, &v, &w);
    			eg[u].push_back(make_pair(v, w));
    			eg[v].push_back(make_pair(u, w));
    		}
    		scanf("%d", &x);
    		printf("Case %d:
    ", cas++);
    		spfa(x);
    		for (int i = 0; i < n; i++) {
    			if(dis[i]>=INF)
    				printf("Impossible
    ");
    			else
    				printf("%d
    ", dis[i]);
    		}
    	}
    	return 0;
    }

    H:LightOJ - 1029 Civil and Evil Engineer:求最小生成树和最大生成树

    #include <stdio.h>
    #include <iostream>
    #include <string.h>
    const int inf = 1e6;
    using namespace std;
     
    int map[1000][1000],Map[1000][1000];
    int dis[10000],vist[10000];
    int MIN = 0,MAX = 0;
    int x;
     
    void minn()
    {
        for(int i = 0; i<=x; i++)
        {
            vist[i] = 0;
            dis[i] = map[0][i];
        }
     
        vist[0] = 1 ;
        for(int i = 1; i<=x; i++)
        {
            int min = inf,pos = 0;
            for(int j = 0; j<=x; j++)
            {
                if(vist[j] == 0 && dis[j] < min)
                {
                    min = dis[j];
                    pos = j;
                }
            }
     
            MIN += min;
            vist[pos] = 1 ;
            for(int j = 0; j<=x; j++)
            {
                if(vist[j] == 0 && dis[j] > map[pos][j])
                {
                    dis[j] = map[pos][j];
                }
            }
        }
    }
    void maxx()
    {
        for(int i = 0; i<=x; i++)
        {
            vist[i] = 0;
            dis[i] = Map[0][i];
        }
     
        vist[0] = 1 ;
        for(int i = 1; i<=x; i++)
        {
            int min = 0,pos = 0;
            for(int j = 0; j<=x; j++)
            {
                if(!vist[j] && dis[j] > min)
                {
                    min = dis[j];
                    pos = j;
                }
            }
            if(pos==0)
                break;
            MAX += min;
            vist[pos] = 1 ;
            for(int j = 0; j<=x; j++)
            {
                if(vist[j]  == 0&& dis[j] < Map[pos][j])
                {
                    dis[j] = Map[pos][j];
                }
            }
        }
    }
    int main()
    {
        int a,b,c,t;
        int cou = 1;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&x);
            memset(Map,0,sizeof(Map));
            memset(map,inf,sizeof (map));
            while(~scanf("%d%d%d",&a,&b,&c))
            {
                if(a==0 &&b==0 &&c==0)
                    break;
                if(c<map[a][b])
                    map[a][b] = map[b][a] = c;
                if(c>Map[a][b])
                    Map[a][b] = Map[b][a] = c;
            }
            MIN = 0;
            MAX = 0;
     
            minn ();
            maxx ();
     
            // printf ("%d %d
    ",MIN,MAX);
            printf ("Case %d: ",cou);
            cou++;
            if ((MIN + MAX) % 2 == 0)
                printf ("%d
    ",(MIN + MAX)/2);
            else printf ("%d/2
    ",MAX+MIN);
        }
        return 0;
    }
  • 相关阅读:
    jquery 第二节 Dom和jQuery的互相转换
    jquery 第一节 什么是jQuery
    SQL四大语句、四大完整性、五大约束
    empty和is_null以及isset函数在0、”0”、‘空串’、NULL、false、array()的计算值
    WAMP常用环境配置
    解读Java内部类
    每日编程系列——暗黑的字符串
    每日编程系列——跳石板
    每日编程系列——优雅的点
    每日编程系列——回文序列
  • 原文地址:https://www.cnblogs.com/shmilky/p/14089007.html
Copyright © 2011-2022 走看看