poj 1273 Drainage Ditches--最大流--sap

来源:互联网 发布:node sass 国内镜像 编辑:程序博客网 时间:2024/05/17 20:00
/*sap的非递归实现  0ms  还不错让人纠结的啊   我写的是吧d[]初始化为0  WA看别人的模版初始化为m,过了又看到别人用数组标记,过了(貌似也不对,居然过了)我写了一个数组标记访问,没过*/#include<stdio.h>#include<string.h>#include<queue>using namespace std;const int N=300;const int inf=0x7fffffff;int  map[N][N];int n,m,src,sink,minf;int d[N],numbs[N],curnode[N],pre[N],vis[N];void revbfs()//初始化距离    {/*int u,v;//我的初始化为0    没过   谁给看看memset(d,0,sizeof(d));memset(numbs,0,sizeof(numbs));d[sink]=0;numbs[0]=1;queue<int>q;q.push(sink);while(!q.empty()){u=q.front();q.pop();for(v=1;v<=m;++v){if(map[v][u]==0||d[v]||v==sink)continue;d[v]=d[u]+1;numbs[d[v]]++;q.push(v);}}return;*//*int i,u; //别人的数组标记访问  过了queue<int>q;memset(vis,0,sizeof(vis));  d[sink]=0;  vis[sink]=true;  q.push(sink);while(!q.empty())  {  u=q.front();q.pop();for(i=1; i<=m;++i)  if(!vis[i] &&map[u][i])  {  d[i]=d[u]+1;  vis[i]=true;  q.push(i);}  }*//*int u,v;//我的素族标记访问  没过memset(numbs,0,sizeof(numbs));memset(vis,0,sizeof(vis));d[sink]=0;numbs[0]=1;vis[sink]=1;queue<int>q;q.push(sink);while(!q.empty()){u=q.front();q.pop();for(v=1;v<=m;++v){if(!vis[v]&&map[v][u]){vis[v]=1;d[v]=d[u]+1;numbs[d[v]]++;q.push(v);}}}return;*//*int u,v;//模板上的  初始化为m   过了for(u=1;u<=m;++u)d[u]=m;memset(numbs,0,sizeof(numbs));d[sink]=0;numbs[0]=1;queue<int>q;q.push(sink);while(!q.empty()){u=q.front();q.pop();for(v=1;v<=m;++v){if(map[v][u]==0||d[v]<m)continue;d[v]=d[u]+1;numbs[d[v]]++;q.push(v);}}*/}int retreat(int &i)//修改d[i]=min(d[j]+1|)     更新相关numbs{int t,mind=m-1,j;//为什么mind=m-1?这就是最大的 for(j=1;j<=m;++j)if(map[i][j]>0&&d[j]<mind)mind=d[j];t=d[i];d[i]=mind+1;numbs[t]--;numbs[d[i]]++;if(i!=src)i=pre[i];//为什么   退回上一层      i中不到允许边了,这个操作试图找到允许边    没有这部分可能会造成死循环return numbs[t];}int augment()//找到最窄的路  然后按那个增广{int i,j;int t=inf;for(i=sink,j=pre[i];i!=src;i=j,j=pre[i]){if(t>map[j][i])t=map[j][i];}for(i=sink,j=pre[i];i!=src;i=j,j=pre[i]){map[j][i]-=t;map[i][j]+=t;}return t;}int sap(){memset(pre,0,sizeof(pre));int i,j;memset(d,0,sizeof(d));//放在这儿  可省去revbfs();revbfs();for(i=1;i<=m;++i)curnode[i]=1;//递归通过这个实现    curnode[i]表示的是i的后继结点的开始位置,小于它的已经访问过了i=src;while(d[src]<m){for(j=curnode[i];j<=m;++j)if(map[i][j]>0&&d[i]==d[j]+1)break;if(j<=m){curnode[i]=j;pre[j]=i;i=j;if(i==sink){minf+=augment();i=src;//这都回去了 怎么实现递归?     通过cuenode实现    curnode是当前路径上的点  所以可以通过这个恢复递归状态}}else{curnode[i]=1;//因为i没有可用的允许边,下面试图通过修改d[i]来寻找新的,若找到,那么新的都还没有搜索过,所以要从1开始if(retreat(i)==0)break;}}return minf;}int main(){int i,a,b,c;while(scanf("%d%d",&n,&m)!=EOF){minf=0;src=1;sink=m;memset(map,0,sizeof(map));for(i=1;i<=n;++i){scanf("%d%d%d",&a,&b,&c);map[a][b]+=c;}printf("%d\n",sap());}}
/*居然用了16ms  用循环写的时候,不用bfs好像也是0ms  这个跟那个好像差不多吧   居然运行了两次都是16ms 谁知道为什么啊*/#include<stdio.h>#include<string.h>int m,n,src,sink;int d[205],num[205];int map[205][205];int min(int a,int b){return a<b?a:b;}int dfs(int u,int f){if(u==sink)return f;int v,mind=n-1,last=f,cost;;for(v=1;v<=n;++v){if(map[u][v]>0)//有流量{if(d[u]==d[v]+1)//有允许边{cost=dfs(v,min(last,map[u][v]));map[u][v]-=cost;//修改图map[v][u]+=cost;last-=cost;//修改剩余流量if(d[src]>=n)//结束标志return f-last;if(last==0)//使用完就退出break;}if(d[v]<mind)//下面更新距离的时候用  求其能连接到的最小距离   这个判断和上边的那个判断并列  因为他们是互斥的,只有当找不到允许边的时候才用得着mindmind=d[v];}}if(last==f)//流量没有使用  即  没有允许边{--num[d[u]];if(num[d[u]]==0)//若出现断层{d[src]=n;}d[u]=mind+1;++num[d[u]];}return f-last;}int sap(){int ret=0;memset(d,0,sizeof(d));//距离memset(num,0,sizeof(num));//距离数num[0]=n;while(d[src]<n)ret+=dfs(src,0x7fffffff);return ret;//最大流}int main(){int i,a,b,c;while(scanf("%d%d",&m,&n)!=EOF){src=1;sink=n;memset(map,0,sizeof(map));for(i=1;i<=m;++i){scanf("%d%d%d",&a,&b,&c);map[a][b]+=c;}printf("%d\n",sap());}return 0;}


原创粉丝点击