标签:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 1545 Accepted Submission(s): 338
网上百度这道题的题解,用的好像都是最大流的方法,不知道效率怎么样,反正我觉得是很麻烦的,我用的这个算法是我自己想的,就是一直重复spfa求最小流的过程,当发现下一个最小流比上一个最小流大的时候,就结束算法,感觉这种算法的效率还是不错的,特意贴出来分享一下。
#include<iostream> #include<cstdio> #include<queue> #include<cstring> #include<climits> #define MAXN 1500*1500 using namespace std; struct Edge { int s,t,f,c,next; } edge[MAXN]; int head[1510]; int pre[1510]; int dist[1510]; bool isq[1510]; int n,s,t,u,v,w,ent; void add(int S,int T,int f,int c) { edge[ent].s=S; edge[ent].t=T; edge[ent].f=f; edge[ent].c=c; edge[ent].next=head[S]; head[S]=ent++; edge[ent].s=T; edge[ent].t=S; edge[ent].f=0; edge[ent].c=-c; edge[ent].next=head[T]; head[T]=ent++; } int MIN(int a,int b) { return a<b?a:b; } void init() { ent=0; memset(head,-1,sizeof(head)); while(scanf("%d%d%d",&u,&v,&w),u+v+w) { add(u,v,1,w); add(v,u,1,w); } } bool spfa() { memset(pre,-1,sizeof(pre));//初始化路径为-1 for(int i=s; i<=t; i++) { isq[i]=false;//每点开始时均不在队列里面 dist[i]=INT_MAX;//初始化到每点的最小费用均为INT_MAX } queue<int>q; q.push(s); isq[s]=true;//源点s已经放入到队列里面去了 dist[s]=0;//从源点到源点的距离为0 while(!q.empty())//当队列为空时优化过程结束,退出循环 { int temp1=q.front(); q.pop(); isq[temp1]=false;//该点已经退出队列 for(int i=head[temp1]; i!=-1; i=edge[i].next) //从该点找通过邻接表找所有的以该点为起点的边,从中找出能优化的点 { int temp2=edge[i].t; if(edge[i].f&&dist[temp2]>dist[temp1]+edge[i].c) { dist[temp2]=dist[temp1]+edge[i].c; pre[temp2]=i; if(!isq[temp2])//如果该点不在队列中,则将该点放入队列中 { q.push(temp2); isq[temp2]=true; } } } } return pre[t]!=-1;//如果pre[t]==-1的话说明没有找到从s到t的路径,即已经找到所有的路径了,结束循环 } void mcmf() { int tot=0; int mincost=INT_MAX; int minn=INT_MAX; while(spfa()) { if(dist[t]<=mincost) { tot++; mincost=dist[t]; } else break;//当新求出来的最小费用大于初始的那个的时候结束算法 for(int i=pre[t];i!=-1;i=pre[i])//最小费用最大流中的减流的过程 { edge[i].f--; edge[i^1].f++; i=edge[i].s; } } printf("%d\n",tot); } int main() { int cas; scanf("%d",&cas); while(cas--) { scanf("%d",&n); s=1;t=n; init(); mcmf(); } }
标签:
原文地址:http://www.cnblogs.com/lthb/p/4424954.html