图的相关操作总结

本文深入探讨了图的各种基本操作,包括深度优先遍历、广度优先遍历等,并介绍了如何判断无向图是否存在环,输出特定长度的路径,以及普利姆算法生成最小生成树等内容。此外还提供了拓扑排序的具体实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

图的相关操作总结

  1. 递归深度优先遍历
  2. 非递归深度优先遍历
  3. 广度优先遍历
  4. 判断无向图是否有环
  5. 输出vi到vj的长度为l的路径
  6. 找出经过vi的回路
  7. 普利姆算法
  8. 拓扑排序

部分操作参考:http://blog.csdn.net/Kay_Sprint/article/category/851272/1

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define MAX_SIZE 100

//邻接矩阵
struct vertex {//顶点
	int num;//顶点的编号
	char data;//顶点的信息
};

typedef struct graph{//图
	int n;//图中顶点的个数
	int e;//图中边的个数
	struct vertex vexs[MAX_SIZE];//顶点集合
	int edges[MAX_SIZE][MAX_SIZE];//边的集合;无权时为0,1;有权时是其:0;权值。
}AdjMaxix;

//邻接矩阵
typedef struct ArcNode{//表结点
	int adjverx;//邻接点序号
	char info;//邻接点信息
	struct ArcNode *nextarc;//下一个邻接点
}ArcNode;

typedef struct verxnode{//顶点结点
	char data;//顶点信息
	struct ArcNode *firstarc;//指向第一个邻接点
}AdjList;

//初始化访问标志位为0
int visited[8] = {0,0,0,0,0,0,0,0};
void initVisited(){
	int i = 0;
	for (i = 0;i< 8;i++){
		visited[i] = 0;
	}
}

//建立邻接矩阵的图
AdjMaxix createGraphStoredByMatrix(){
	AdjMaxix  adj;

	adj.n = 8;
	adj.e = 10;

	int i = 0,j = 0;
	for (i = 0;i < adj.n;i++){
		adj.vexs[i].num = i;
		adj.vexs[i].data = 'a' + i;
		for (j = 0;j< adj.n;j++){
			adj.edges[i][j] = 0;
		}
	}
	adj.edges[0][1]= 1;
	adj.edges[0][2]= 1;

	adj.edges[1][0]= 1;
	adj.edges[1][3]= 1;
	adj.edges[1][4]= 1;

	adj.edges[2][0]= 1;
	adj.edges[2][5]= 1;
	adj.edges[2][6]= 1;

	adj.edges[3][1]= 1;
	adj.edges[3][7]= 1;

	adj.edges[4][1]= 1;
	adj.edges[4][7]= 1;

	adj.edges[5][2]= 1;
	adj.edges[5][7]= 1;

	adj.edges[6][2]= 1;
	adj.edges[6][7]= 1;

	adj.edges[7][3]= 1;
	adj.edges[7][4]= 1;
	adj.edges[7][5]= 1;
	adj.edges[7][6]= 1;

	return adj;
}
//建立邻接表的图
AdjList* createGraphStoredByTable(){

	
	AdjList *g = new AdjList[8];

	

	int i = 0,j = 0;

	for (i = 0;i <8 ;i++){

		g[i].data = '0'+i;
		g[i].firstarc = NULL;
	}

	ArcNode *node1 = (ArcNode*)malloc(sizeof(ArcNode));
	node1->adjverx = 1;
	node1->nextarc = NULL;
	ArcNode *node2 = (ArcNode*)malloc(sizeof(ArcNode));
	node2->adjverx = 2;
	node2->nextarc = NULL;

	node1->nextarc = node2;
	g[0].firstarc = node1;

	ArcNode *node3 = (ArcNode*)malloc(sizeof(ArcNode));
	node3->adjverx = 0;
	node3->nextarc = NULL;
	ArcNode *node4 = (ArcNode*)malloc(sizeof(ArcNode));
	node4->adjverx = 3;
	node4->nextarc = NULL;
	ArcNode *node5 = (ArcNode*)malloc(sizeof(ArcNode));
	node5->adjverx = 4;
	node5->nextarc = NULL;


	node3->nextarc = node4;
	node4->nextarc = node5;
	g[1].firstarc = node3;


	ArcNode *node6 = (ArcNode*)malloc(sizeof(ArcNode));
	node6->adjverx = 0;
	node6->nextarc = NULL;
	ArcNode *node7 = (ArcNode*)malloc(sizeof(ArcNode));
	node7->adjverx = 5;
	node7->nextarc = NULL;
	ArcNode *node8 = (ArcNode*)malloc(sizeof(ArcNode));
	node8->adjverx = 6;
	node8->nextarc = NULL;

	node6->nextarc = node7;
	node7->nextarc = node8;
	g[2].firstarc = node6;

	ArcNode *node9 = (ArcNode*)malloc(sizeof(ArcNode));
	node9->adjverx = 1;
	node9->nextarc = NULL;
	ArcNode *node10 = (ArcNode*)malloc(sizeof(ArcNode));
	node10->adjverx = 7;
	node10->nextarc = NULL;

	node9->nextarc = node10;
	g[3].firstarc = node9;


	ArcNode *node11 = (ArcNode*)malloc(sizeof(ArcNode));
	node11->adjverx = 1;
	node11->nextarc = NULL;
	ArcNode *node12 = (ArcNode*)malloc(sizeof(ArcNode));
	node12->adjverx = 7;
	node12->nextarc = NULL;

	node11->nextarc = node12;
	g[4].firstarc = node11;

	ArcNode *node13 = (ArcNode*)malloc(sizeof(ArcNode));
	node13->adjverx = 2;
	node13->nextarc = NULL;
	ArcNode *node14 = (ArcNode*)malloc(sizeof(ArcNode));
	node14->adjverx = 7;
	node14->nextarc = NULL;

	node13->nextarc = node14;
	g[5].firstarc = node13;

	ArcNode *node15 = (ArcNode*)malloc(sizeof(ArcNode));
	node15->adjverx = 2;
	node15->nextarc = NULL;
	ArcNode *node16 = (ArcNode*)malloc(sizeof(ArcNode));
	node16->adjverx = 7;
	node16->nextarc = NULL;

	node15->nextarc = node16;
	g[6].firstarc = node15;

	
	ArcNode *node17 = (ArcNode*)malloc(sizeof(ArcNode));
	node17->adjverx = 3;
	node17->nextarc = NULL;
	ArcNode *node18 = (ArcNode*)malloc(sizeof(ArcNode));
	node18->adjverx = 4;
	node18->nextarc = NULL;
	ArcNode *node19 = (ArcNode*)malloc(sizeof(ArcNode));
	node19->adjverx = 5;
	node19->nextarc = NULL;
	ArcNode *node20 = (ArcNode*)malloc(sizeof(ArcNode));
	node20->adjverx = 6;
	node20->nextarc = NULL;

	node17->nextarc = node18;
	node18->nextarc = node19;
	node19->nextarc = node20;
	g[7].firstarc = node17;
	

	return g;

}
//有向图
AdjList* createGraphStoredByTable2(){


	AdjList *g = new AdjList[8];



	int i = 0,j = 0;

	for (i = 0;i <8 ;i++){

		g[i].data = '0'+i;
		g[i].firstarc = NULL;
	}

	ArcNode *node1 = (ArcNode*)malloc(sizeof(ArcNode));
	node1->adjverx = 1;
	node1->nextarc = NULL;
	ArcNode *node2 = (ArcNode*)malloc(sizeof(ArcNode));
	node2->adjverx = 7;
	node2->nextarc = NULL;

	node1->nextarc = node2;
	//g[0].firstarc = node1;

	g[0].firstarc = node1;

	/*ArcNode *node3 = (ArcNode*)malloc(sizeof(ArcNode));
	node3->adjverx = 0;
	node3->nextarc = NULL;*/
	ArcNode *node4 = (ArcNode*)malloc(sizeof(ArcNode));
	node4->adjverx = 3;
	node4->nextarc = NULL;
	ArcNode *node5 = (ArcNode*)malloc(sizeof(ArcNode));
	node5->adjverx = 4;
	node5->nextarc = NULL;


	//node3->nextarc = node4;
	node4->nextarc = node5;
	g[1].firstarc = node4;


	/*ArcNode *node6 = (ArcNode*)malloc(sizeof(ArcNode));
	node6->adjverx = 0;
	node6->nextarc = NULL;*/
	ArcNode *node7 = (ArcNode*)malloc(sizeof(ArcNode));
	node7->adjverx = 1;
	node7->nextarc = NULL;
	ArcNode *node8 = (ArcNode*)malloc(sizeof(ArcNode));
	node8->adjverx = 6;
	node8->nextarc = NULL;

	//node6->nextarc = node7;
	node7->nextarc = node8;
	g[2].firstarc = node7;

	ArcNode *node9 = (ArcNode*)malloc(sizeof(ArcNode));
	node9->adjverx = 5;
	node9->nextarc = NULL;
	//ArcNode *node10 = (ArcNode*)malloc(sizeof(ArcNode));
	//node10->adjverx = 7;
	//node10->nextarc = NULL;

	//node9->nextarc = node10;
	g[3].firstarc = node9;


	ArcNode *node11 = (ArcNode*)malloc(sizeof(ArcNode));
	node11->adjverx = 5;
	node11->nextarc = NULL;
	/*ArcNode *node12 = (ArcNode*)malloc(sizeof(ArcNode));
	node12->adjverx = 7;
	node12->nextarc = NULL;*/

	//node11->nextarc = node12;
	g[4].firstarc = node11;

	ArcNode *node13 = (ArcNode*)malloc(sizeof(ArcNode));
	node13->adjverx = 6;
	node13->nextarc = NULL;
	/*ArcNode *node14 = (ArcNode*)malloc(sizeof(ArcNode));
	node14->adjverx = 7;
	node14->nextarc = NULL;*/

	//node13->nextarc = node14;
	g[5].firstarc = node13;

	ArcNode *node15 = (ArcNode*)malloc(sizeof(ArcNode));
	node15->adjverx = 7;
	node15->nextarc = NULL;
	/*ArcNode *node16 = (ArcNode*)malloc(sizeof(ArcNode));
	node16->adjverx = 7;
	node16->nextarc = NULL;*/

	//node15->nextarc = node16;
	g[6].firstarc = node15;


	ArcNode *node17 = (ArcNode*)malloc(sizeof(ArcNode));
	node17->adjverx = 0;
	node17->nextarc = NULL;
	/*ArcNode *node18 = (ArcNode*)malloc(sizeof(ArcNode));
	node18->adjverx = 4;
	node18->nextarc = NULL;
	ArcNode *node19 = (ArcNode*)malloc(sizeof(ArcNode));
	node19->adjverx = 5;
	node19->nextarc = NULL;
	ArcNode *node20 = (ArcNode*)malloc(sizeof(ArcNode));
	node20->adjverx = 6;
	node20->nextarc = NULL;

	node17->nextarc = node18;
	node18->nextarc = node19;
	node19->nextarc = node20;*/
	g[7].firstarc = node17;


	return g;

}

void printData(char c){
	printf("%c",c);
}


void dfs(AdjList* list, int adjverx){
	visited[adjverx] = 1;
	printData(list[adjverx].data);
	ArcNode* p = list[adjverx].firstarc;
	//在这里访问的是边,因此为e
	while (p != NULL){
		if (!visited[p->adjverx]){
			dfs(list,p->adjverx);
		}
		p = p ->nextarc;
	}
}
//递归深度优先遍历 邻接矩阵 时间复杂度为O(n+e)
void dfsTraverse(){

	AdjList* list = createGraphStoredByTable();
	//printf("%c",list[0].data);
	int i = 0;
	int count = 0 ;
	//dfs(list,7);
	//顶点个数n
	for(i = 0;i<8;i++){
		if (!visited[i]){
			count++;
			dfs(list,i);
		}
	}
	printf("\nThe parts of the graph is %d",count);
}

//非递归的深度优先遍历
//采用先访问,在入栈的方式。
void dfsTraverse2(){
	int i = 0;
	int stack[MAX_SIZE];
	int top = -1;
	AdjList* list = createGraphStoredByTable();

	ArcNode* p = NULL;
	int j = 0;

	for (i = 0;i<8;i++){
		if (!visited[i]){
			//图的第一个元素入栈。
			visited[i] = 1;
			printData(list[i].data);
			stack[++top] = i;

			while(top > -1){
				//访问栈顶而不是退出栈,因为,有可能这个点还有很多邻接点没有访问到。
				j = stack[top];
				//图的第一个邻接点
				p = list[j].firstarc;
				//关键点,这个地方非常厉害,从第一个点开始判断,直到其将所有的邻接点判断完毕。
				while (p != NULL && visited[p->adjverx] == 1){
					p = p->nextarc;
				}
				//如果为空,证明,这个点所在的所有邻接点都访问过了,因此退栈。
				if (p == NULL){
					top--;
				} else {
					//先访问再进栈,然后,将再从第一个邻接点开始访问。
					j = p->adjverx;
					printData(list[j].data);
					visited[j] = 1;
					stack[++top] = j;
				}

			}
		}
	}
}



//广度优先遍历 时间复杂度O(n+e)
void BFSTraverse(){
	AdjList* list = createGraphStoredByTable();

	ArcNode* queue[MAX_SIZE];
	int front = 0,rear  = 0;
	
	ArcNode* p ;

	int i = 0;
	//顶点数n
	for (i= 0 ;i<8;i++){
		if (!visited[i]){
			printf("%c",list[i].data);
			visited[i] = 1;
			//在这里不用判断是否访问过,因为没有一个结点与本连通,因此其肯定没有访问过。
			if (list[i].firstarc == NULL ){
				//除去只有一个结点的情况
				continue;
			}

			//将第一个结点压入站
			queue[rear++] = list[i].firstarc;
			p = list[i].firstarc;
			p = p->nextarc;
			//这个是有记忆功能的对弧的遍历e
			while(rear != front){
				
				while(p != NULL){
					//保证入栈的全部是没有访问的元素
					if (!visited[p->adjverx]){
						queue[rear++] = p;
					}
					p = p->nextarc;
				}

				//出栈
				p = queue[front++];
				if (!visited[p->adjverx]){
					visited[p->adjverx] = 1;
					printData(list[p->adjverx].data);
					//p出栈之后,将p的所有自都压入栈中。
					p = list[p->adjverx].firstarc;
				}

			}
		}

	}

}

//广度优先遍历 推荐
void BFSTraverse2(){
	AdjList* list = createGraphStoredByTable();

	AdjList queue[MAX_SIZE];
	int front = 0,rear  = 0;

	AdjList temp ;

	ArcNode* p ;

	int i = 0;
	//对于每个顶点
	for (i= 0 ;i<8;i++){
		if (!visited[i]){
			//对每个顶点判断
			printData(list[i].data);
			visited[i] = 1;
			queue[rear++] = list[i];

			while(rear != front){
				//出队列
				temp = queue[front++];
				p = temp.firstarc;

				while(p != NULL){
					//保证入栈的全部是没有访问的元素
					if (!visited[p->adjverx]){
						printData(list[p->adjverx].data);
						visited[p->adjverx] = 1;
						
						queue[rear++] = list[p->adjverx];
					}
					p = p->nextarc;
				}

			}
		}
	}

}




//判断无向图是否有环 第一种方案
/************************************************************************/
//递归依次删除度数为1的节点,如果最后仍然存在未删除的那么图中有环
/*  第一步:删除所有度<=1的顶点及相关的边,并将另外与这些边相关的其它顶点的度减一。  
    第二步:将度数变为1的顶点排入队列,并从该队列中取出一个顶点重复步骤一。  
    如果最后还有未删除顶点,则存在环,否则没有环。                       */
/************************************************************************/

//判断无向图是否有环 第二种方案(采用改进版的深度优先遍历)
//参考:http://bbs.csdn.net/topics/190057901  中willshy的解答;
//同时参考:http://daoluan.net/blog/%E3%80%90%E5%9B%BE%E8%AE%BA%E3%80%91%E5%88%A4%E6%96%AD%E6%9C%89%E5%90%91%E5%9B%BE%E6%98%AF%E5%90%A6%E5%AD%98%E5%9C%A8%E7%8E%AF/
/************************************************************************/
/*引入三种状态,而不是之前深度优先访问的两种方案。
   0 白色,未被访问过的节点标白色
   -1 灰色,已经被访问过一次的节点标灰色。主要是为了标识这个点,以这个点位根结点,然后访问其子结点,如果子结点能够回来,说明有环。
	1 黑色,当该节点的所有后代都被访问过标黑色 

	 仍然是按图的节点深度遍历,访问到V时,V若被访问过,那么有2种状态:
	C[V]=-1,程序跳出,存在环
	C[V]=1,程序继续,这不是环

		   时间复杂度O(n+e)  */
/************************************************************************/
int dfsCycle(AdjList* list, int adjverx);
void isCycleOrNot(){
	AdjList * list = createGraphStoredByTable();

	int i = 0;

	for (i = 0;i<8;i++){
		if (visited[i] == 0){
			if (!dfsCycle(list,i)){
				printf("有环\n");
				break;
			}
			
		}
	}
	if (i == 8){
		printf("无环\n");
	}

}
int dfsCycle(AdjList* list, int adjverx){

	visited[adjverx] = -1;
	ArcNode *p = list[adjverx].firstarc;

	while(p != NULL){	
		if (visited[p->adjverx] == 0){
			dfsCycle(list,p->adjverx);
			//说明有环
		} else if (visited[p->adjverx] == -1){
			return 0;
		}

		p = p->nextarc;

	}

	//访问完了,将其置为1。
	visited[adjverx] = 1;

	return 1;

}

/************************************************************************/
/* 简单路径:如果一条路径上的顶点除了起点和终点可以相同外,其它顶点均不相同,
则称此路径为一条简单路径;起点和终点相同的简单路径称为回路(或环)。     */
/************************************************************************/

int path[20]; 
//输出vi到vj的长度为l的路径,参考:http://blog.csdn.net/jkay_wong/article/details/6968260
void Print_X_Y_Path(AdjList* vertices, int u,int v,int l,int d){  
	//求出一条长度为l的从u到v的路径,d刚进来的时候是-1
	int m;  
	int i;
	d++;  
	visited[u]=1;  
	path[d]=u;  

	if(u == v && d == l) {   //找到一条路径
		for(int i=0;i<l;i++) {
			printData(vertices[ path[i] ].data);  
		}
		printData('\n'); 
	} else if(u == v && d!=l) {  
		visited[u]=0;  
		d--;  
	} else {  
		ArcNode *p=vertices[u].firstarc; //继续DFS  
		while(p) {  
			m=p->adjverx;  
			if(!visited[m])  
				Print_X_Y_Path(vertices,m,v,l,d);  
			p=p->nextarc;  
		}  
	}  
	//恢复环境,使顶点可重新使用  
	//路径长度减一  
	visited[u]=0;  
	d--;  
}  
//输出
void Print_X_X_Path(AdjList* vertices,int i,int j,int d) {  
	//找出从i到i的回路,思想和上面的类似  
	int v,k;  
	ArcNode *p;  
	visited[i]=1;  
	d++;  
	path[d]=i;  
	if(i == j && d>2){  
		for(k=0;k<d;k++){
			printData(vertices[path[i]].data);  
		}
		printData('\n');
	}  else if(i == j && d==2) {
		visited[i]=0;  
		d--; 
	} else  {  //一条边只可以走一次  
		p=vertices[i].firstarc;  
		while(p)  
		{  
			v=p->adjverx;  
			if(!visited[v] || v == j)  
				Print_X_X_Path(vertices,v,j,d);  
			p=p->nextarc;  
		}  
	}  


	visited[i]=0;  
	d--;  
}  


typedef struct Tree_Edge{  
	int star;  
	int end;  
	int weight; 
}Tree_Edge ;

int vexnum = 8;
int arcs[MAX_SIZE][MAX_SIZE]; 

//Prime 普利姆算法最小生成树
//从v点出发,输出g的最小生成树
void Prim_Min_Tree(int v, Tree_Edge c[]) { 

	int lowcast[MAX_SIZE]; //存放当前点到各个点的权值 
	int closet[MAX_SIZE];  //存放已经进入最小树的值
	int i,min,j,k; 

	 /*   初始化数组lowcast closet  */ 
	for(i=0;i<vexnum;i++) {  
		//放v到各个顶点的权值
		lowcast[i]=arcs[v][i];
		//现在最短路径集合中只有v顶点,下标为终点,值为起点。
		closet[i]=v;  
	}  
	//将v到顶点的权值设置为0
	lowcast[v]=0;  

	for(i=1;i<vexnum;i++){  
		min=MAX_SIZE;  
		for(j=0;j<vexnum;j++){  
			if(lowcast[j]!=0 && lowcast[j]<min) {  
				min=lowcast[j];  
				k=j;  
			}  
		}  
		lowcast[k]=0; //标志该顶点已经是U中顶点  

		c[i].star=closet[k];  
		c[i].end=k;  
		c[i].weight=min;  

		//下面是修改lowcast和closet  
		//因为终点为k,所以现在以k为起点,找到比原先小的值放入集合中
		for(j=0;j<vexnum;j++){  
			if(arcs[k][j]<lowcast[j]){  
				lowcast[j]=arcs[k][j];  
				closet[j]=k;  
			}  
		}  
	}  

	printf("最小生成树 完成~~");
}   /*   求最小生成树的Prime算法   */ 

/************************************************************************/
/* 克鲁斯卡尔算法    :主要使用了并查集的算法,用于判断新加入的结点是否已经在现有结点当中,防止出现环的情况。
	1、首先对所有的路径排序
	2、发现新加入结点的组号,(采用二叉树的parent-link改进的find方法)
	3、如果两个组号相同,则表示已经在连接组内,如果不同,则放入连接组,并更改其中一个结点的组
	4、判断连接组中的k值是否与图中结点数相同。

	参考:http://blog.csdn.net/jkay_wong/article/details/6975151
	并查集参考:http://blog.csdn.net/dm_vincent/article/details/7655764
*/
/************************************************************************/


int indegree[8];
//临界表查找指定结点的入度
void getInDegree(AdjList * list){

	int i = 0;
	
	for (i = 0;i<8;i++){
		indegree[i] = 0;
	}
	ArcNode * p = NULL;
	for (i = 0;i < 8 ;i++){
		p = list[i].firstarc;
		while(p != NULL){
			indegree[p->adjverx]++;
			p = p->nextarc;
		}
	}
	
}

//拓扑排序 aov
 void Topo_Sort() {
	
	 //有向图
	 AdjList * list = createGraphStoredByTable2();
	 //得到所有结点的入度
	 getInDegree(list);
	 int queue[MAX_SIZE] ;
	 int front = 0,rear = 0,i = 0;

	 ArcNode * p ;
	 //将入度为0 的元素入队列
	 for (i = 0;i<8;i++){
		 if (indegree[i] == 0){
			 queue[rear++] = i;
		 }
	 }
	 int temp =0;
	 int count = 0;
	 while(front != rear){
		 temp = queue[front++];
		 printData(list[temp].data);
		 p = list[temp].firstarc;
		 count ++;
		 while(p != NULL){
			//将以其为弧尾的弧所对应的弧头结点的入度 减一。
			indegree[p->adjverx]--;

			//判断入度是否为0
			if (indegree[p->adjverx] == 0){
				//如果为0则,将其入队列,进行下一次出队列操作。
				queue[rear++] = p->adjverx;
			}

			p = p ->nextarc;
		 }
	 }
	 if (count < 8){
		 printf("\n改图有环\n");
	 }
 }

 /************************************************************************/
 /* 
  * 求AOE网的关键路径参考:http://blog.csdn.net/jkay_wong/article/details/6696701
 */
 /************************************************************************/

 /************************************************************************/
 /*求最短路径之——Dijkstra算法,参考:http://blog.csdn.net/jkay_wong/article/details/6692572
 */
 /************************************************************************/



void main(){
	
	printf("深度优先遍历:\n");
	dfsTraverse();
	printf("\n\n");
	
	initVisited();
	printf("广度优先遍历:\n");
	BFSTraverse();
	printf("\n\n");
	initVisited();
	BFSTraverse2();
	printf("\n\n");

	printf("检查无向图是否有环:\n");
	initVisited();
	isCycleOrNot();
	printf("\n\n");
	printf("拓扑排序:\n");
	Topo_Sort();
	printf("\n\n");


}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值