ISAP算法

        最短增广路算法(SAP),采用广度优先的方法在残余网络中找去权值的最短增广路。从源点到汇点,像声音传播一样,总是找到最短的路径。在寻找路径时却多搜索了很多结点。

        30e7d437951d407586e6146b18b18fd5.png

        有人想到了一条妙计—贴标签。首先对所有的结点标记到汇点的最短距离,我们称之为高度。标高从汇点开始,用广度优先的方式,汇点的邻接点高度1,继续访问的结点高度是2,一直到源点结束。

ba39de83bbee4b31bf6c1bd41b4dd3c6.png 

        贴好标签之后,从源点开始,沿着高度h(u)=h(v)+1且有可行邻接边(cap>flow)的方向前进,例如:h(1)=3,h(2)=2,h(4)= 1,h(6)=0。很快找到了汇点,然后沿着可增广路1—2—4—6增减流之后的残余网络。

        1e95adfff722469daca0b8aff200729d.png 

        再次从源点开始搜索,沿着高度h(u)= h(v)+1且有可行邻接边(cap>flow)的方向前进,h(1)=3,h(2)=2,走到这里无法走到4号结点,因为没有邻接边,3号结点不仅没有邻接边而且高度也不满足条件。也不能走到1号结点,因为h(1)=3。怎么办呢?

565fc816383d4a95880452138d354c54.png 

        重贴标签:当前结点无法前进时,令当前结点的高度=所有邻接点高度的最小值+1;如果没有邻接边,则令当前结点的高度=结点数;退回一步;重新搜索。重贴标签后,h(2)= h(1)+1=4,退回一步到1号结点,重新搜索。

        cee273d607924d7782919c368e07766b.png 

        算法设计:

        (1)确定合适数据结构。采用链式前向星存储混合网络。

         (2)对网络结点贴标签,即标高操作。

        (3)找可增广路。如果源点的高度≥结点数,算法结束;否则从源点开始,沿着高度h(u)=h(v)+1且有可行邻接边(cap>flow)的方向前进,如果到达汇点,则转向第4步;如果无法行进,则转向第5步。 

        (4)增流操作:沿着找到的可增广路同向边增流,反向边减流。

        (5)重贴标签:如果拥有当前结点高度的结点只有一个,则转向第6步;令当前结点的高度=所有邻接点高度的最小值+1;如果没有可行邻接边,则令当前结点的高度=结点数;退回一步;转向第3步。

        (6)算法结束,已经找到最大流。

        在重贴标签之前判断当前高度为d[u]的结点个数是1,立即结束。

        这是ISAP算法的重要优化,可以提前结束程序,很多时候提速非常明显(高达100倍以上)。

         当前结点u无法行进时,说明u、t之间的连通性消失,但如果u是最后一个和t距离d[u]的点,说明此时s、t也不连通了。这是因为,虽然u、t已经不连通,但毕竟我们走的是最短路,其他点此时到t的距离一定大于d[u],因此其他点要到t,必然要经过一个和t距离为d[u]的点。

        f9f56b20f5514aedb2fe2131432ca4bf.png

        利用标签算法求解网络最大流。

43215629028f4e6a860ac1a2a21e6d65.png 

        (1)时间复杂度:从算法描述中可以看出,找到一条可增广路的时间是O(V),最多会执行O(VE)次,因为关键边的总数为O(VE),因此总的时间复杂度为O(V2E),其中V为结点个数,E为边的数量。

       (2)空间复杂度:空间复杂度为O(V)。 

        

hdu2732 ISAP
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=1010;
const int M=1000100;
int cnt;
int head[N],pre[N],h[N],g[N];
struct Edge{
   int v,next;
   int cap,flow;
}E[M<<1];//双边

void init(){//初始化 
    memset(head,-1,sizeof(head));
    cnt=0;
}

void add(int u,int v,int c){
    E[cnt].v=v;
    E[cnt].cap=c;
    E[cnt].flow=0;
    E[cnt].next=head[u];
    head[u]=cnt++;
}

void adde(int u,int v,int c){
    add(u,v,c);
    add(v,u,0);
}

void set_h(int t,int n){//标高 
    queue<int> q;
    memset(h,-1,sizeof(h));
    memset(g,0,sizeof(g));
    h[t]=0;
    q.push(t);
    while(!q.empty()){
		int u=q.front();q.pop();
		++g[h[u]];//高度为h[u]的节点个数
		for(int i=head[u];~i;i=E[i].next){
			int v=E[i].v;
			if(h[v]==-1){
				h[v]=h[u]+1;
				q.push(v);
			}
        }
    }
}

int ISAP(int s,int t,int n){
    set_h(t,n);
    int ans=0,u=s,d;
    while(h[s]<n){
        int i=head[u];
        if(u==s)
           d=inf;
        for(;~i;i=E[i].next){
			int v=E[i].v;
			if(E[i].cap>E[i].flow&&h[u]==h[v]+1){
				u=v;
                pre[v]=i;
                d=min(d,E[i].cap-E[i].flow);
                if(u==t){
					while(u!=s){
						int j=pre[u];
						E[j].flow+=d;
						E[j^1].flow-=d;
						u=E[j^1].v;
					}
					ans+=d;
					//d=inf;
                }
                break;
            }
        }
        if(i==-1){
			if(--g[h[u]]==0)
				break;
			int hmin=n-1;
			for(int j=head[u];~j;j=E[j].next)
				if(E[j].cap>E[j].flow)
					hmin=min(hmin,h[E[j].v]);
			h[u]=hmin+1;
			++g[h[u]];
			if(u!=s)
				u=E[pre[u]^1].v;
        }
    }
    return ans;
}

int main(){
    int T,cas=0;
    string s;
	scanf("%d",&T);
    while(T--){
        int n,m,d,src,dst;
        int sum=0;//蜥蜴数
        scanf("%d%d",&n,&d);
        for(int i=0;i<n;i++){
            cin>>s;
            if(i==0){//第一次读入 
                m=s.size();
                src=0,dst=2*n*m+1;
                init();
            }
            for(int j=0;j<s.size();j++)
				if(s[j]-'0'>0){ //大于0的拆点 
	                int id=i*m+j+1; //当前点编号
	                adde(id,id+n*m,s[j]-'0');
	                if(i<d||i+d>=n||j<d||j+d>=m)//当前格子能直接跳出棋盘
	                    adde(id+n*m,dst,inf);
	                else{ //不能直接跳出去
	                    for(int k=0;k<n;k++)
		                    for(int h=0;h<m;h++){
		                        int id2=k*m+h+1;
		                        if(id==id2) continue;
		                        if(abs(i-k)+abs(j-h)<=d)
									adde(id+n*m,id2,inf);
		                    }
	                }
            	}
        }
        for(int i=0;i<n;i++){
            cin>>s;
            for(int j=0;j<s.size();j++){
                int id=i*m+j+1;//当前点编号
                if(s[j]=='L'){
                    ++sum;
                    adde(src,id,1);
                }
            }
        }
        int ans=sum-ISAP(src,dst,dst+1);
        if(ans==0) printf("Case #%d: no lizard was left behind.\n",++cas);
        else if(ans==1) printf("Case #%d: 1 lizard was left behind.\n",++cas);
        else printf("Case #%d: %d lizards were left behind.\n",++cas,ans);
    }
    return 0;
}
hdu280 Dinic
#include<cstdio>//G++ 9703ms
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=100010;
const int M=200010;
int cnt;
int head[N],d[N];
struct Edge{
   int v,next;
   int cap,flow;
}E[M<<1];//双边

void init(){//初始化 
    memset(head,-1,sizeof(head));
    cnt=0;
}

void add(int u,int v,int c){
    E[cnt].v=v;
    E[cnt].cap=c;
    E[cnt].flow=0;
    E[cnt].next=head[u];
    head[u]=cnt++;
}

void adde(int u,int v,int c){
    add(u,v,c);
    add(v,u,0);
}

bool bfs(int s,int t){//分层
    memset(d,0,sizeof(d));
    queue<int>q;
    d[s]=1;
    q.push(s);
    while(!q.empty()){
        int u=q.front();
        q.pop();
        for(int i=head[u];~i;i=E[i].next){
        	int v=E[i].v;
        	if(!d[v]&&E[i].cap>E[i].flow){
                d[v]=d[u]+1;
				q.push(v);
				if(v==t)  return 1;
			}	
		}
    }
    return 0;
}

int dfs(int u,int flow,int t){//在分层的基础上dfs 
    if(u==t) return flow;
	int rest=flow;
    for(int i=head[u];~i&&rest;i=E[i].next){
    	int v=E[i].v;
    	if(d[v]==d[u]+1&&E[i].cap>E[i].flow){
            int k=dfs(v,min(rest,E[i].cap-E[i].flow),t);
			if(!k) d[v]=0;
			E[i].flow+=k;
			E[i^1].flow-=k;
			rest-=k;
		}	
	}
	return flow-rest;
}

int Dinic(int s,int t){
	int maxflow=0;
	while(bfs(s,t)){
		maxflow+=dfs(s,inf,t);
	}
	return maxflow;
}

int main(){
	int T,n,m,s,t;
    scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		int minx=inf;
		int maxx=-inf;
		for(int i=1;i<=n;i++){
			int x,y;
			scanf("%d%d",&x,&y);
			if(x>maxx){
				maxx=x;
				t=i;
			}
			if(minx>x){
				minx=x;
				s=i;
			}
		}//找到源点和汇点。 
		init();
		while(m--){
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			adde(u,v,w);
			adde(v,u,w);
		}
		printf("%d\n",Dinic(s,t));
	} 
    return 0;
}
hdu4280 ISAP
#include<cstdio>//5366ms
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=100010;
const int M=200010;
int cnt;
int head[N],pre[N],h[N],g[N];
struct Edge{
   int v,next;
   int cap,flow;
}E[M<<1];//双边

void init(){//初始化 
    memset(head,-1,sizeof(head));
    cnt=0;
}

void add(int u,int v,int c){
    E[cnt].v=v;
    E[cnt].cap=c;
    E[cnt].flow=0;
    E[cnt].next=head[u];
    head[u]=cnt++;
}

void adde(int u,int v,int c){
    add(u,v,c);
    add(v,u,0);
}

void set_h(int t,int n){//标高 
    queue<int> q;
    memset(h,-1,sizeof(h));
    memset(g,0,sizeof(g));
    h[t]=0;
    q.push(t);
    while(!q.empty()){
		int u=q.front();q.pop();
		++g[h[u]];//高度为h[u]的节点个数
		for(int i=head[u];~i;i=E[i].next){
			int v=E[i].v;
			if(h[v]==-1){
				h[v]=h[u]+1;
				q.push(v);
			}
        }
    }
}

int ISAP(int s,int t,int n){
    set_h(t,n);
    int ans=0,u=s,d;
    while(h[s]<n){
        int i=head[u];
        if(u==s)
           d=inf;
        for(;~i;i=E[i].next){
			int v=E[i].v;
			if(E[i].cap>E[i].flow&&h[u]==h[v]+1){
				u=v;
                pre[v]=i;
                d=min(d,E[i].cap-E[i].flow);
                if(u==t){
					while(u!=s){
						int j=pre[u];
						E[j].flow+=d;
						E[j^1].flow-=d;
						u=E[j^1].v;
					}
					ans+=d;
					//d=inf;
                }
                break;
            }
        }
        if(i==-1){
			if(--g[h[u]]==0)
				break;
			int hmin=n-1;
			for(int j=head[u];~j;j=E[j].next)
				if(E[j].cap>E[j].flow)
					hmin=min(hmin,h[E[j].v]);
			h[u]=hmin+1;
			++g[h[u]];
			if(u!=s)
				u=E[pre[u]^1].v;
        }
    }
    return ans;
}

int main(){
	int T,n,m,s,t;
    scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		int minx=inf;
		int maxx=-inf;
		for(int i=1;i<=n;i++){
			int x,y;
			scanf("%d%d",&x,&y);
			if(x>maxx){
				maxx=x;
				t=i;
			}
			if(minx>x){
				minx=x;
				s=i;
			}
		}//找到源点和汇点。 
		init();
		while(m--){
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			adde(u,v,w);//双向! 
			adde(v,u,w);//双向!
		}
		printf("%d\n",ISAP(s,t,n));
	} 
    return 0;
}
ISAP
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=100;
const int M=10000;
int cnt,d;
int head[N],pre[N],h[N],g[N];
struct Edge{
   int v,next;
   int cap,flow;
}E[M];

void init(){//初始化 
    memset(head,-1,sizeof(head));
    cnt=0;
}

void add(int u,int v,int c){
    E[cnt].v=v;
    E[cnt].cap=c;
    E[cnt].flow=0;
    E[cnt].next=head[u];
    head[u]=cnt++;
}

void set_h(int t,int n){//标高 
    queue<int> q;
    memset(h,-1,sizeof(h));
    memset(g,0,sizeof(g));
    h[t]=0;
    q.push(t);
    while(!q.empty()){
		int u=q.front();q.pop();
		++g[h[u]];//高度为h[u]的节点个数
		for(int i=head[u];~i;i=E[i].next){
			int v=E[i].v;
			if(h[v]==-1){
				h[v]=h[u]+1;
				q.push(v);
			}
        }
    }
    cout<<"初始化高度"<<endl;
    cout<<"h[ ]=";
    for(int i=1;i<=n;i++)
       cout<<"\t"<<h[i];
    cout<<endl;
}

int ISAP(int s,int t,int n){
    set_h(t,n);
    int ans=0,u=s,d;
    while(h[s]<n){
        int i=head[u];
		if(u==s)
           d=inf;
        for(;~i;i=E[i].next){
			int v=E[i].v;
			if(E[i].cap>E[i].flow&&h[u]==h[v]+1){
				u=v;
                pre[v]=i;
                d=min(d,E[i].cap-E[i].flow);
                if(u==t){
					cout<<endl;
					cout<<"增广路径:"<<t;
					while(u!=s){
						int j=pre[u];
						E[j].flow+=d;
						E[j^1].flow-=d;
						u=E[j^1].v;
						cout<<"--"<<u;
					}
					cout<<"增流:"<<d<<endl;
					ans+=d;
					d=inf;
                }
                break;
            }
        }
		if(i==-1){
			if(--g[h[u]]==0)
				break;
			int hmin=n-1;
			for(int j=head[u];~j;j=E[j].next)
				if(E[j].cap>E[j].flow)
					hmin=min(hmin,h[E[j].v]);
			h[u]=hmin+1;
			cout<<"重贴标签后高度"<<endl;
			cout<<"h[ ]=";
			for(int i=1;i<=n;i++)
				cout<<"  "<<h[i];
			cout<<endl;
			++g[h[u]];
			if(u!=s)
				u=E[pre[u]^1].v;
		}	
    }
    return ans;
}

void printg(int n){//输出网络
	cout<<endl;
	cout<<"----------网络(链式前向星):----------"<<endl;
	for(int i=1;i<=n;i++){
		cout<<"v"<<i<<"  ["<<head[i];
		for(int j=head[i];~j;j=E[j].next)
			cout<<"]--["<<E[j].v<<"\t"<<E[j].cap<<"\t"<<E[j].flow<<"\t"<<E[j].next;
		cout<<"]"<<endl;
   }
   cout<<endl;
}

void printflow(int n){//输出实流边
	cout<<endl;
	cout<<"----------实流边:----------"<<endl;
	for(int i=1;i<=n;i++)
		for(int j=head[i];~j;j=E[j].next)
			if(E[j].flow>0){
				cout<<"v"<<i<<"--"<<"v"<<E[j].v<<"\t"<<E[j].flow;
				cout<<endl;
        	}
}
/*
请输入结点个数n和边数m:
6 9
1 3 10
1 2 12
2 4 8
3 5 13
3 2 2
4 6 18
4 3 5
5 6 4
5 4 6
*/
int main(){
    int n,m;
    int u,v,w;
    cout<<"请输入结点个数n和边数m:"<<endl;
    cin>>n>>m;
    init();
    cout<<"请输入两个结点u,v及边(u--v)的容量w:"<<endl;
    for(int i=1;i<=m;i++){
        cin>>u>>v>>w;
        add(u,v,w);
        add(v,u,0);
    }
    cout<<endl;
    printg(n);//输出初始网络
    cout<<"网络的最大流值:"<<ISAP(1,n,n)<<endl;
    cout<<endl;
    printg(n);//输出最终网络
    printflow(n);//输出实流边
    return 0;
}
POJ3281 ISAP
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=410;
const int M=20500;
int cnt;
int head[N],pre[N],h[N],g[N];
struct Edge{
   int v,next;
   int cap,flow;
}E[M<<1];//双边

void init(){//初始化 
    memset(head,-1,sizeof(head));
    cnt=0;
}

void add(int u,int v,int c){
    E[cnt].v=v;
    E[cnt].cap=c;
    E[cnt].flow=0;
    E[cnt].next=head[u];
    head[u]=cnt++;
}

void adde(int u,int v,int c){
    add(u,v,c);
    add(v,u,0);
}

void set_h(int t,int n){//标高 
    queue<int> q;
    memset(h,-1,sizeof(h));
    memset(g,0,sizeof(g));
    h[t]=0;
    q.push(t);
    while(!q.empty()){
		int u=q.front();q.pop();
		++g[h[u]];//高度为h[u]的节点个数
		for(int i=head[u];~i;i=E[i].next){
			int v=E[i].v;
			if(h[v]==-1){
				h[v]=h[u]+1;
				q.push(v);
			}
        }
    }
}

int ISAP(int s,int t,int n){
    set_h(t,n);
    int ans=0,u=s,d;
    while(h[s]<n){
        int i=head[u];
        if(u==s)
           d=inf;
        for(;~i;i=E[i].next){
			int v=E[i].v;
			if(E[i].cap>E[i].flow&&h[u]==h[v]+1){
				u=v;
                pre[v]=i;
                d=min(d,E[i].cap-E[i].flow);
                if(u==t){
					while(u!=s){
						int j=pre[u];
						E[j].flow+=d;
						E[j^1].flow-=d;
						u=E[j^1].v;
					}
					ans+=d;
					//d=inf;
                }
                break;
            }
        }
        if(i==-1){
			if(--g[h[u]]==0)
				break;
			int hmin=n-1;
			for(int j=head[u];~j;j=E[j].next)
				if(E[j].cap>E[j].flow)
					hmin=min(hmin,h[E[j].v]);
			h[u]=hmin+1;
			++g[h[u]];
			if(u!=s)
				u=E[pre[u]^1].v;
        }
    }
    return ans;
}

int main(){
    int n,f,d,k,x,y;
	scanf("%d%d%d",&n,&f,&d);
	int s=0,t=f+2*n+d+1;
	init();
	for(int i=1;i<=f;i++)//源点到食物连边 
        adde(s,i,1);
    for(int i=1;i<=n;i++)//牛到牛拆点连边 
        adde(f+i,f+n+i,1);  
    for(int i=1;i<=d;i++)//饮料到汇点连边 
        adde(f+2*n+i,t,1);
    for(int i=1;i<=n;i++){
    	scanf("%d%d",&x,&y);
    	for(int j=1;j<=x;j++){//食物到牛入点连边 
        	scanf("%d",&k);
			adde(k,f+i,1);
		}
		for(int j=1;j<=y;j++){//牛出点到饮料连边 
        	scanf("%d",&k);
			adde(f+n+i,f+2*n+k,1);
		}
	}
	printf("%d\n",ISAP(s,t,t+1));
	return 0;
}
POJ3436 ISAP
#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>
using namespace std;
const int inf=0x3f3f3f3f;
const int N=110;
const int M=10100;
int n,m;
int cnt;
int head[N],pre[N],h[N],g[N];
int num[N];
int input[N][20],output[N][20];
int vis[N][N];
struct Edge{
   int v,next;
   int cap,flow;
}E[M<<1];//双边

void init(){//初始化 
    memset(head,-1,sizeof(head));
    memset(vis,0,sizeof vis);
    cnt=0;
}

void add(int u,int v,int c){
    E[cnt].v=v;
    E[cnt].cap=c;
    E[cnt].flow=0;
    E[cnt].next=head[u];
    head[u]=cnt++;
}

void adde(int u,int v,int c){
    add(u,v,c);
    add(v,u,0);
}

void set_h(int t,int n){//标高 
    queue<int> q;
    memset(h,-1,sizeof(h));
    memset(g,0,sizeof(g));
    h[t]=0;
    q.push(t);
    while(!q.empty()){
		int u=q.front();q.pop();
		++g[h[u]];//高度为h[u]的节点个数
		for(int i=head[u];~i;i=E[i].next){
			int v=E[i].v;
			if(h[v]==-1){
				h[v]=h[u]+1;
				q.push(v);
			}
        }
    }
}

int ISAP(int s,int t,int n){
    set_h(t,n);
    int ans=0,u=s,d;
    while(h[s]<n){
        int i=head[u];
        if(u==s)
           d=inf;
        for(;~i;i=E[i].next){
			int v=E[i].v;
			if(E[i].cap>E[i].flow&&h[u]==h[v]+1){
				u=v;
                pre[v]=i;
                d=min(d,E[i].cap-E[i].flow);
                if(u==t){
					while(u!=s){
						int j=pre[u];
						E[j].flow+=d;
						E[j^1].flow-=d;
						u=E[j^1].v;
					}
					ans+=d;
					//d=inf;
                }
                break;
            }
        }
        if(i==-1){
			if(--g[h[u]]==0)
				break;
			int hmin=n-1;
			for(int j=head[u];~j;j=E[j].next)
				if(E[j].cap>E[j].flow)
					hmin=min(hmin,h[E[j].v]);
			h[u]=hmin+1;
			++g[h[u]];
			if(u!=s)
				u=E[pre[u]^1].v;
        }
    }
    return ans;
}

bool check(int x,int y){
    return x==y||y==2;
}

bool ck1(int d){ //没有1
    for(int i=1;i<=n;i++)
        if(input[d][i]==1) return false;
    return true;
}

bool ck2(int d){ //全1
    for(int i=1;i<=n;i++)
        if(output[d][i]!=1) return false;
    return true;
}

int main(){
    while(~scanf("%d%d",&n,&m)){
        for(int i=1;i<=m;i++){
            scanf("%d",&num[i]);
            for(int j=1;j<=n;j++)
                scanf("%d",&input[i][j]);
            for(int j=1;j<=n;j++)
                scanf("%d",&output[i][j]);
        }
        init();
        for(int i=1;i<=m;i++)
            for(int j=1;j<=m;j++){
                if(i==j) continue;
                bool flag=true;
                for(int k=1;k<=n;k++)
                    if(!check(output[i][k],input[j][k])){
                        flag=false;
                        break;
                    }
                if(flag){
                    adde(i+m,j,num[i]);
                    //cout<<i+m<<"\t"<<j<<"\t"<<num[i]<<endl;
                    vis[i+m][j]=1;
                }
            }
        for(int i=1;i<=m;i++){
            adde(i,i+m,num[i]);//拆点
            if(ck1(i)) adde(0,i,num[i]);
            if(ck2(i)) adde(i+m,2*m+1,num[i]);
        }
        printf("%d",ISAP(0,2*m+1,2*m+2));
        int cnt=0;
        for(int i=1;i<=m;i++)
            for(int j=head[i+m];~j;j=E[j].next)
                if(vis[i+m][E[j].v]&&E[j].flow>0) cnt++;//连接数 
        printf(" %d\n",cnt);
        for(int i=1;i<=m;i++)
            for(int j=head[i+m];~j;j=E[j].next)
                if(vis[i+m][E[j].v]&&E[j].flow>0)
                    printf("%d %d %d\n",i,E[j].v,E[j].flow);//机器A B flow 
    }
	return 0;
}

 

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值