1.最大流
ps:直接以题目来看模板的使用
POJ - 1459 Power Network(最大流)(模板)
d.看了好久,囧。
n个节点,np个源点,nc个汇点,m条边(对应代码中即节点u 到节点v 的最大流量为z)
求所有汇点的最大流。
s.多个源点,多个汇点的最大流。
建立一个超级源点、一个超级汇点,然后求超级源点到超级汇点的最大流即可。
c.SAP邻接矩阵形式:
/* SAP算法(矩阵形式) 结点编号从0开始 */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int MAXN=128; int maze[MAXN][MAXN]; int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN]; int sap(int start,int end,int nodenum){ memset(cur,0,sizeof(cur)); memset(dis,0,sizeof(dis)); memset(gap,0,sizeof(gap)); int u=pre[start]=start,maxflow=0,aug=-1; gap[0]=nodenum; while(dis[start]<nodenum){ loop: for(int v=cur[u];v<nodenum;v++) if(maze[u][v]&&dis[u]==dis[v]+1){ if(aug==-1||aug>maze[u][v])aug=maze[u][v]; pre[v]=u; u=cur[u]=v; if(v==end){ maxflow+=aug; for(u=pre[u];v!=start;v=u,u=pre[u]){ maze[u][v]-=aug; maze[v][u]+=aug; } aug=-1; } goto loop; } int mindis=nodenum-1; for(int v=0;v<nodenum;v++) if(maze[u][v]&&mindis>dis[v]){ cur[u]=v; mindis=dis[v]; } if((--gap[dis[u]])==0)break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } int main(){ int n,np,nc,m;//节点总数,源点,汇点,边数 int u,v,z;//节点u,节点v,最大流量z char str[5];//处理空格 int sp,sc;//超级源点,超级汇点 while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){ memset(maze,0,sizeof(maze)); for(int i=0;i<m;++i){ scanf("%1s%d%1s%d%1s%d",str,&u,str,&v,str,&z); maze[u][v]=z; } //建立超级源点 sp=n++; for(int i=0;i<np;++i){ scanf("%1s%d%1s%d",str,&u,str,&z); maze[sp][u]=z; } //建立超级汇点 sc=n++; for(int i=0;i<nc;++i){ scanf("%1s%d%1s%d",str,&u,str,&z); maze[u][sc]=z; } printf("%d ",sap(sp,sc,n)); } return 0; }
c2.SAP邻接矩阵形式2:
/* 保留原矩阵,可用于多次使用最大流 SAP邻接矩阵形式 点的编号从0开始 增加个flow数组,保留原矩阵maze,可用于多次使用最大流 */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int MAXN=128; int maze[MAXN][MAXN]; int gap[MAXN],dis[MAXN],pre[MAXN],cur[MAXN]; int flow[MAXN][MAXN];//存最大流的容量 int sap(int start,int end,int nodenum){ memset(cur,0,sizeof(cur)); memset(dis,0,sizeof(dis)); memset(gap,0,sizeof(gap)); memset(flow,0,sizeof(flow)); int u=pre[start]=start,maxflow=0,aug=-1; gap[0]=nodenum; while(dis[start]<nodenum){ loop: for(int v=cur[u];v<nodenum;v++) if(maze[u][v]-flow[u][v]&&dis[u]==dis[v]+1){ if(aug==-1||aug>maze[u][v]-flow[u][v])aug=maze[u][v]-flow[u][v]; pre[v]=u; u=cur[u]=v; if(v==end){ maxflow+=aug; for(u=pre[u];v!=start;v=u,u=pre[u]){ flow[u][v]+=aug; flow[v][u]-=aug; } aug=-1; } goto loop; } int mindis=nodenum-1; for(int v=0;v<nodenum;v++) if(maze[u][v]-flow[u][v]&&mindis>dis[v]){ cur[u]=v; mindis=dis[v]; } if((--gap[dis[u]])==0)break; gap[dis[u]=mindis+1]++; u=pre[u]; } return maxflow; } int main(){ int n,np,nc,m;//节点总数,源点,汇点,边数 int u,v,z;//节点u,节点v,最大流量z char str[5];//处理空格 int sp,sc;//超级源点,超级汇点 while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){ memset(maze,0,sizeof(maze)); for(int i=0;i<m;++i){ scanf("%1s%d%1s%d%1s%d",str,&u,str,&v,str,&z); maze[u][v]=z; } //建立超级源点 sp=n++; for(int i=0;i<np;++i){ scanf("%1s%d%1s%d",str,&u,str,&z); maze[sp][u]=z; } //建立超级汇点 sc=n++; for(int i=0;i<nc;++i){ scanf("%1s%d%1s%d",str,&u,str,&z); maze[u][sc]=z; } printf("%d ",sap(sp,sc,n)); } return 0; }
c3.ISAP邻接表形式:注意一下边数的范围
/* ISAP邻接表形式 */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int MAXN=128;//点数的最大值 const int MAXM=20500;//边数的最大值(加的双向加,所以是2倍,别忘了加上超级源点和超级汇点(共400条)) const int INF=0x3f3f3f3f; struct Edge{ int to,next,cap,flow; }edge[MAXM];//注意是MAXM int tol; int head[MAXN]; int gap[MAXN],dep[MAXN],pre[MAXN],cur[MAXN]; void init(){ tol=0; memset(head,-1,sizeof(head)); } //加边,单向图三个参数,双向图四个参数 void addedge(int u,int v,int w,int rw=0){ edge[tol].to=v;edge[tol].cap=w;edge[tol].next=head[u]; edge[tol].flow=0;head[u]=tol++; edge[tol].to=u;edge[tol].cap=rw;edge[tol].next=head[v]; edge[tol].flow=0;head[v]=tol++; } //输入参数:起点、终点、点的总数 //点的编号没有影响,只要输入点的总数 int sap(int start,int end,int N){ memset(gap,0,sizeof(gap)); memset(dep,0,sizeof(dep)); memcpy(cur,head,sizeof(head)); int u=start; pre[u]=-1; gap[0]=N; int ans=0; while(dep[start]<N){ if(u==end){ int Min=INF; for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]) if(Min>edge[i].cap-edge[i].flow) Min=edge[i].cap-edge[i].flow; for(int i=pre[u];i!=-1;i=pre[edge[i^1].to]){ edge[i].flow+=Min; edge[i^1].flow-=Min; } u=start; ans+=Min; continue; } bool flag=false; int v; for(int i=cur[u];i!=-1;i=edge[i].next){ v=edge[i].to; if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u]){ flag=true; cur[u]=pre[v]=i; break; } } if(flag){ u=v; continue; } int Min=N; for(int i=head[u];i!=-1;i=edge[i].next) if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min){ Min=dep[edge[i].to]; cur[u]=i; } gap[dep[u]]--; if(!gap[dep[u]])return ans; dep[u]=Min+1; gap[dep[u]]++; if(u!=start)u=edge[pre[u]^1].to; } return ans; } int main(){ int n,np,nc,m;//节点总数,源点,汇点,边数 int u,v,z;//节点u,节点v,最大流量z char str[5];//处理空格 int sp,sc;//超级源点,超级汇点 while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){ init(); for(int i=0;i<m;++i){ scanf("%1s%d%1s%d%1s%d",str,&u,str,&v,str,&z); addedge(u,v,z); } //建立超级源点 sp=n++; for(int i=0;i<np;++i){ scanf("%1s%d%1s%d",str,&u,str,&z); addedge(sp,u,z); } //建立超级汇点 sc=n++; for(int i=0;i<nc;++i){ scanf("%1s%d%1s%d",str,&u,str,&z); addedge(u,sc,z); } printf("%d ",sap(sp,sc,n)); } return 0; }
c4.ISAP+bfs初始化+栈优化:注意一下边数的范围
/* ISAP+bfs初始化+栈优化 */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int MAXN=128;//点数的最大值 const int MAXM=20500;//边数的最大值 const int INF=0x3f3f3f3f; struct Edge{ int to,next,cap,flow; }edge[MAXM];//注意是MAXM int tol; int head[MAXN]; int gap[MAXN],dep[MAXN],cur[MAXN]; void init(){ tol=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int w,int rw=0){ edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=0; edge[tol].next=head[u];head[u]=tol++; edge[tol].to=u;edge[tol].cap=rw;edge[tol].flow=0; edge[tol].next=head[v];head[v]=tol++; } int Q[MAXN]; void BFS(int start,int end){ memset(dep,-1,sizeof(dep)); memset(gap,0,sizeof(gap)); gap[0]=1; int front=0,rear=0; dep[end]=0; Q[rear++]=end; while(front!=rear){ int u=Q[front++]; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(dep[v]!=-1)continue; Q[rear++]=v; dep[v]=dep[u]+1; gap[dep[v]]++; } } } int S[MAXN]; int sap(int start,int end,int N){ BFS(start,end); memcpy(cur,head,sizeof(head)); int top=0; int u=start; int ans=0; while(dep[start]<N){ if(u==end){ int Min=INF; int inser; for(int i=0;i<top;i++) if(Min>edge[S[i]].cap-edge[S[i]].flow){ Min=edge[S[i]].cap-edge[S[i]].flow; inser=i; } for(int i=0;i<top;i++){ edge[S[i]].flow+=Min; edge[S[i]^1].flow-=Min; } ans+=Min; top=inser; u=edge[S[top]^1].to; continue; } bool flag=false; int v; for(int i=cur[u];i!=-1;i=edge[i].next){ v=edge[i].to; if(edge[i].cap-edge[i].flow&&dep[v]+1==dep[u]){ flag=true; cur[u]=i; break; } } if(flag){ S[top++]=cur[u]; u=v; continue; } int Min=N; for(int i=head[u];i!=-1;i=edge[i].next) if(edge[i].cap-edge[i].flow&&dep[edge[i].to]<Min){ Min=dep[edge[i].to]; cur[u]=i; } gap[dep[u]]--; if(!gap[dep[u]])return ans; dep[u]=Min+1; gap[dep[u]]++; if(u!=start)u=edge[S[--top]^1].to; } return ans; } int main(){ int n,np,nc,m;//节点总数,源点,汇点,边数 int u,v,z;//节点u,节点v,最大流量z char str[5];//处理空格 int sp,sc;//超级源点,超级汇点 while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){ init(); for(int i=0;i<m;++i){ scanf("%1s%d%1s%d%1s%d",str,&u,str,&v,str,&z); addedge(u,v,z); } //建立超级源点 sp=n++; for(int i=0;i<np;++i){ scanf("%1s%d%1s%d",str,&u,str,&z); addedge(sp,u,z); } //建立超级汇点 sc=n++; for(int i=0;i<nc;++i){ scanf("%1s%d%1s%d",str,&u,str,&z); addedge(u,sc,z); } printf("%d ",sap(sp,sc,n)); } return 0; }
c5.dinic:注意一下边数的范围
/* dinic */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int MAXN=128;//点数的最大值 const int MAXM=20500;//边数的最大值 const int INF=0x3f3f3f3f; struct Edge{ int to,next,cap,flow; }edge[MAXM];//注意是MAXM int tol; int head[MAXN]; void init(){ tol=2; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int w,int rw=0){ edge[tol].to=v;edge[tol].cap=w;edge[tol].flow=0; edge[tol].next=head[u];head[u]=tol++; edge[tol].to=u;edge[tol].cap=rw;edge[tol].flow=0; edge[tol].next=head[v];head[v]=tol++; } int Q[MAXN]; int dep[MAXN],cur[MAXN],sta[MAXN]; bool bfs(int s,int t,int n){ int front=0,tail=0; memset(dep,-1,sizeof(dep[0])*(n+1)); dep[s]=0; Q[tail++]=s; while(front<tail){ int u=Q[front++]; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(edge[i].cap>edge[i].flow&&dep[v]==-1){ dep[v]=dep[u]+1; if(v==t)return true; Q[tail++]=v; } } } return false; } int dinic(int s,int t,int n){ int maxflow=0; while(bfs(s,t,n)){ for(int i=0;i<n;i++)cur[i]=head[i]; int u=s,tail=0; while(cur[s]!=-1){ if(u==t){ int tp=INF; for(int i=tail-1;i>=0;i--) tp=min(tp,edge[sta[i]].cap-edge[sta[i]].flow); maxflow+=tp; for(int i=tail-1;i>=0;i--){ edge[sta[i]].flow+=tp; edge[sta[i]^1].flow-=tp; if(edge[sta[i]].cap-edge[sta[i]].flow==0) tail=i; } u=edge[sta[tail]^1].to; } else if(cur[u]!=-1&&edge[cur[u]].cap>edge[cur[u]].flow&&dep[u]+1==dep[edge[cur[u]].to]){ sta[tail++]=cur[u]; u=edge[cur[u]].to; } else{ while(u!=s&&cur[u]==-1) u=edge[sta[--tail]^1].to; cur[u]=edge[cur[u]].next; } } } return maxflow; } int main(){ int n,np,nc,m;//节点总数,源点,汇点,边数 int u,v,z;//节点u,节点v,最大流量z char str[5];//处理空格 int sp,sc;//超级源点,超级汇点 while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){ init(); for(int i=0;i<m;++i){ scanf("%1s%d%1s%d%1s%d",str,&u,str,&v,str,&z); addedge(u,v,z); } //建立超级源点 sp=n++; for(int i=0;i<np;++i){ scanf("%1s%d%1s%d",str,&u,str,&z); addedge(sp,u,z); } //建立超级汇点 sc=n++; for(int i=0;i<nc;++i){ scanf("%1s%d%1s%d",str,&u,str,&z); addedge(u,sc,z); } printf("%d ",dinic(sp,sc,n)); } return 0; }
以上算法均取自kuangbin模板,ac时间均不到100ms。
下面补上一个增广路算法(EdmondsKarp算法),但是时间让人捉急,1000多ms
c6.增广路算法(EdmondsKarp算法):
/* 增广路算法(EdmondsKarp算法) */ #include<iostream> #include<stdio.h> #include<vector> #include<string.h> #include<queue> using namespace std; const int maxn=128; const int INF=0x3f3f3f3f; struct Edge{ int from,to,cap,flow; Edge(int u,int v,int c,int f):from(u),to(v),cap(c),flow(f){} }; struct EdmondsKarp{ int n,m;//n好像没用到 vector<Edge>edges;//边数的两倍 vector<int>G[maxn];//邻接表,G[i][j]表示结点i的第j条边在e数组中的序号 int a[maxn];//当起点到i的可改进量 int p[maxn];//最短路树上p的入弧编号 void init(int n){ for(int i=0;i<n;i++)G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap){ edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0));//反向弧 m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } int Maxflow(int s,int t){ int flow=0; for(;;){ memset(a,0,sizeof(a)); queue<int>Q; Q.push(s); a[s]=INF; while(!Q.empty()){ int x=Q.front();Q.pop(); for(int i=0;i<G[x].size();i++){ Edge &e=edges[G[x][i]]; if(!a[e.to]&&e.cap>e.flow){ p[e.to]=G[x][i]; a[e.to]=min(a[x],e.cap-e.flow); Q.push(e.to); } } if(a[t])break; } if(!a[t])break; for(int u=t;u!=s;u=edges[p[u]].from){ edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; } flow+=a[t]; } return flow; } }EK; int main(){ int n,np,nc,m;//节点总数,源点,汇点,边数 int u,v,z;//节点u,节点v,最大流量z char str[5];//处理空格 int sp,sc;//超级源点,超级汇点 while(~scanf("%d%d%d%d",&n,&np,&nc,&m)){ EK.init(n+2);//加上下面增加的超级源点和超级汇点 for(int i=0;i<m;++i){ scanf("%1s%d%1s%d%1s%d",str,&u,str,&v,str,&z); EK.AddEdge(u,v,z); } //建立超级源点 sp=n++; for(int i=0;i<np;++i){ scanf("%1s%d%1s%d",str,&u,str,&z); EK.AddEdge(sp,u,z); } //建立超级汇点 sc=n++; for(int i=0;i<nc;++i){ scanf("%1s%d%1s%d",str,&u,str,&z); EK.AddEdge(u,sc,z); } printf("%d ",EK.Maxflow(sp,sc)); } return 0; }
2.最小费用最大流
c.Bellman-Ford
/* Bellman-Ford */ #include<iostream> #include<stdio.h> #include<vector> #include<string.h> #include<queue> using namespace std; const int maxn=1024; const int INF=0x3f3f3f3f; struct Edge{ int from,to,cap,flow,cost; Edge(int u,int v,int c,int f,int w):from(u),to(v),cap(c),flow(f),cost(w){} }; struct MCMF{ int n,m; vector<Edge>edges; vector<int>G[maxn]; int inq[maxn];//是否在队列中 int d[maxn];//Bellman-Ford int p[maxn];//上一条弧 int a[maxn];//可改进量 void init(int n){ this->n=n; for(int i=0;i<n;i++)G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int cap,int cost){ edges.push_back(Edge(from,to,cap,0,cost)); edges.push_back(Edge(to,from,0,0,-cost)); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool BellmanFord(int s,int t,int &flow,long long &cost){ for(int i=0;i<n;i++)d[i]=INF; memset(inq,0,sizeof(inq)); d[s]=0;inq[s]=1;p[s]=0;a[s]=INF; queue<int>Q; Q.push(s); while(!Q.empty()){ int u=Q.front();Q.pop(); inq[u]=0; for(int i=0;i<G[u].size();i++){ Edge &e=edges[G[u][i]]; if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){ d[e.to]=d[u]+e.cost; p[e.to]=G[u][i]; a[e.to]=min(a[u],e.cap-e.flow); if(!inq[e.to]){Q.push(e.to);inq[e.to]=1;} } } } if(d[t]==INF)return false; flow+=a[t]; cost+=(long long)d[t]*(long long)a[t]; for(int u=t;u!=s;u=edges[p[u]].from){ edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; } return true; } //需要保证初始网络中没有负权圈 int MincostMaxflow(int s,int t,long long &cost){ int flow=0;cost=0; while(BellmanFord(s,t,flow,cost)); return flow; } }; int main(){ return 0; }
c2.SPFA版费用流
/* SPFA版费用流 最小费用最大流,求最大费用最大流只需要取相反数,结果取相反数即可。 点的总数为N,点的编号0~N-1 */ #include<iostream> #include<stdio.h> #include<string.h> #include<queue> using namespace std; const int MAXN=10000; const int MAXM=100000; const int INF=0x3f3f3f3f; struct Edge{ int to,next,cap,flow,cost; }edge[MAXM]; int head[MAXN],tol; int pre[MAXN],dis[MAXN]; bool vis[MAXN]; int N;//节点总个数,节点编号从0~N-1 void init(int n){ N=n; tol=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int cap,int cost){ edge[tol].to=v; edge[tol].cap=cap; edge[tol].cost=cost; edge[tol].flow=0; edge[tol].next=head[u]; head[u]=tol++; edge[tol].to=u; edge[tol].cap=0; edge[tol].cost=-cost; edge[tol].flow=0; edge[tol].next=head[v]; head[v]=tol++; } bool spfa(int s,int t){ queue<int>q; for(int i=0;i<N;i++){ dis[i]=INF; vis[i]=false; pre[i]=-1; } dis[s]=0; vis[s]=true; q.push(s); while(!q.empty()){ int u=q.front(); q.pop(); vis[u]=false; for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(edge[i].cap>edge[i].flow&&dis[v]>dis[u]+edge[i].cost){ dis[v]=dis[u]+edge[i].cost; pre[v]=i; if(!vis[v]){ vis[v]=true; q.push(v); } } } } if(pre[t]==-1)return false; else return true; } //返回的是最大流,cost存的是最小费用 int minCostMaxflow(int s,int t,int &cost){ int flow=0; cost=0; while(spfa(s,t)){ int Min=INF; for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){ if(Min>edge[i].cap-edge[i].flow) Min=edge[i].cap-edge[i].flow; } for(int i=pre[t];i!=-1;i=pre[edge[i^1].to]){ edge[i].flow+=Min; edge[i^1].flow-=Min; cost+=edge[i].cost*Min; } flow+=Min; } return flow; } int main(){ return 0; }
c3.zkw费用流
/* zkw费用流 对于二分图类型的比较高效 */ #include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int MAXN=100; const int MAXM=20000; const int INF=0x3f3f3f3f; struct Edge{ int to,next,cap,flow,cost; Edge(int _to=0,int _next=0,int _cap=0,int _flow=0,int _cost=0): to(_to),next(_next),cap(_cap),flow(_flow),cost(_cost){} }edge[MAXM]; struct ZKW_MinCostMaxFlow{ int head[MAXN],tot; int cur[MAXN]; int dis[MAXN]; bool vis[MAXN]; int ss,tt,N;//源点、汇点和点的总个数(编号是0~N-1),不需要额外赋值,调用会直接赋值 int min_cost,max_flow; void init(){ tot=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int cap,int cost){ edge[tot]=Edge(v,head[u],cap,0,cost); head[u]=tot++; edge[tot]=Edge(u,head[v],0,0,-cost); head[v]=tot++; } int aug(int u,int flow){ if(u==tt)return flow; vis[u]=true; for(int i=cur[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(edge[i].cap>edge[i].flow&&!vis[v]&&dis[u]==dis[v]+edge[i].cost){ int tmp=aug(v,min(flow,edge[i].cap-edge[i].flow)); edge[i].flow+=tmp; edge[i^1].flow-=tmp; cur[u]=i; if(tmp)return tmp; } } return 0; } bool modify_label(){ int d=INF; for(int u=0;u<N;u++) if(vis[u]) for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(edge[i].cap>edge[i].flow&&!vis[v]) d=min(d,dis[v]+edge[i].cost-dis[u]); } if(d==INF)return false; for(int i=0;i<N;i++) if(vis[i]){ vis[i]=false; dis[i]+=d; } return true; } /* 直接调用获取最小费用和最大流 输入:start-源点,end-汇点,n-点的总个数(编号从0开始) 返回值:pair<int,int>第一个是最小费用,第二个是最大流 */ pair<int,int> mincostmaxflow(int start,int end,int n){ ss=start,tt=end,N=n; min_cost=max_flow=0; for(int i=0;i<n;i++)dis[i]=0; while(1){ for(int i=0;i<n;i++)cur[i]=head[i]; while(1){ for(int i=0;i<n;i++)vis[i]=false; int tmp=aug(ss,INF); if(tmp==0)break; max_flow+=tmp; min_cost+=tmp*dis[ss]; } if(!modify_label())break; } return make_pair(min_cost,max_flow); } }solve; int main(){ return 0; }
c4.这哥们的代码效率挺高,也挺清晰。可以参考。