邻接表--建图、spfa、EK算法 (转化为最小费用最大流)

来源:互联网 发布:python snmp 编辑:程序博客网 时间:2024/05/19 15:21
<pre name="code" class="cpp">#include <iostream>#include <cstdio>#include <algorithm>#include <cstdio>#include <algorithm>#include <cmath>#include <cstring>#include <string.h>#include <queue>#include <vector>         #define inf 1<<30     //poj2135(邻接表--建图、spfa、EK算法)      #define N 1010using namespace std;/*总结:邻接表相对于邻接矩阵要好得多,一方面它不用考虑是否会重边,因为在下面的操作下会在重边的情况下取得最佳的结果,另一方面它相对于邻接矩阵要节省空间另外,要注意邻接表的数组要开大点*/struct Edge{int u, v, w, cap, next;    //使用邻接表,u表示起点,v表示终点,w表示费用(相当于最短路),cap表示容量}edge[50010];   //注意,邻接表的数组要开大点int n, m, index, pre[N], dis[N], vis[N], p[N];queue<int> q;void add(int a, int b, int k, int c){edge[index].u=a;edge[index].v=b;edge[index].w=c;edge[index].cap=k;edge[index].next=pre[a];pre[a]=index++;edge[index].u=b;edge[index].v=a;edge[index].w=-c;  //注意,同条线段相反方向权值为-c,容量为0edge[index].cap=0;edge[index].next=pre[b];pre[b]=index++;return ;}void init()  //构图  {int a, b, c;memset(pre, -1, sizeof(pre));while(m--){scanf("%d%d%d", &a, &b, &c);//注意这里的线段是双向的add(a, b, 1, c);   //一条线段就要上面的两个操作add(b, a, 1, c); }add(0, 1, 2, 0); //以下建立超级源点0和超级汇点n+1,其他点从1开始add(n, n+1, 2, 0);return ;}int mpmf(){int t, s=0, flow, totprice=0, g=n+1, u;while(!q.empty())q.pop();while(1)    //spfa算法{for(t=0; t<=g; ++t){dis[t]=inf;vis[t]=0;}dis[s]=0;    //注意起点不能改变vis[s]=1;q.push(s);while(!q.empty()){u=q.front();q.pop();vis[u]=0;for(t=pre[u]; t!=-1; t=edge[t].next){if(edge[t].cap&&dis[edge[t].v]>dis[u]+edge[t].w){dis[edge[t].v]=dis[u]+edge[t].w;p[edge[t].v]=t;  //这里记录的方法和邻接矩阵不同,记录的是尾点在edge数组的位置if(!vis[edge[t].v]){vis[edge[t].v]=1;q.push(edge[t].v);}}}}if(dis[g]==inf)break;for(t=g, flow=inf; t!=s; t=edge[p[t]].u)  //取线路中的最小流量{if(edge[p[t]].cap<flow)flow=edge[p[t]].cap;  }for(t=g; t!=s; t=edge[p[t]].u)   //更新流量{edge[p[t]].cap-=flow;edge[p[t]^1].cap+=flow;}totprice+=dis[g]*flow;  //最小费用最大流}return totprice;}int main(){while(scanf("%d%d", &n, &m)!=EOF){index=0;init();  //初始化邻接表printf("%d\n", mpmf());}return 0;}

	
				
		
原创粉丝点击