以前都是拿邻接矩阵来实现,这道题的数据里有重边,所以不得不用邻接表了。
现学了一下,用的是前向星数据结构。可以把前向星想象成链表,next是指针,再具体点就是上一条边的索引(要知道上一条边指的是什么,看我代码内的注释)。head[u]是以u为起点的所有边的入口
但这么实现还是比较麻烦,感觉用vector会好一些。
还有我虽然函数名字叫dinic,但我实际上并不是,只是懒得改了。(因为dinic是一次找到多条增广路)
以后我贴代码不加行号了
#include<iostream> #include<queue> #include<cstring> #define INF 1e9 #define MAXN 1005 using namespace std; int n,ans; int dist[1005],pre[1005],head[1005];//head[u]为以u为起点的边的第一边的index,用next来遍历所有以u为起点的边 struct edge{ int v,cost,cap,reverse,next; }edges[MAXN*MAXN]; int cnt; void addedge(int u,int v,int cost,int cap){ edges[cnt].v=v; edges[cnt].cost=cost; edges[cnt].reverse=cnt+1; edges[cnt].cap=cap; edges[cnt].next=head[u];//上一个以u为起点的边的索引 head[u]=cnt++;//更新以u为起点的边的索引,之前位置上的以u为起点的边可以通过现在记录的边的next找到 //反向边 edges[cnt].v=u; edges[cnt].cost=-cost; edges[cnt].reverse=cnt-1; edges[cnt].cap=0; edges[cnt].next=head[v]; head[v]=cnt++; } bool spfa(){ for(int i=0;i<=n+1;i++) dist[i]=INF; queue<int> q; dist[0]=0; pre[0]=-1;//到达0这个点的上一条边是-1 q.push(0); while(!q.empty()){ int u=q.front(); q.pop(); for(int i=head[u];i!=-1;i=edges[i].next){ int v = edges[i].v; if( edges[i].cap>0 && dist[v]>dist[u]+edges[i].cost ){ dist[v]=dist[u]+edges[i].cost; pre[v]=i; q.push(v); } } } if( dist[n+1]==INF ) return false; return true; } void dinic(){ while( spfa() ){ //退流等价于从汇点到源点建一条流量为正,代价为负的边 int u=n+1,edg=pre[u]; while(u!=0){ edges[edg].cap-=1; edges[ edges[edg].reverse ].cap +=1; u=edges[ edges[edg].reverse ].v; edg=pre[u]; } ans+=dist[n+1]; } } int main(){ int m; cin>>n>>m; memset(head,-1,sizeof(head)); for(int i=1;i<=m;i++){ int u,v,d; cin>>u>>v>>d; addedge(u,v,d,1); addedge(v,u,d,1); } addedge(0,1,0,2); addedge(n,n+1,0,2); dinic(); cout<<ans; return 0; }