网络流dinic模板 hdu3549

来源:互联网 发布:哪里有淘宝内部券券 编辑:程序博客网 时间:2024/04/28 15:54

Flow Problem

Time Limit: 5000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 15280    Accepted Submission(s): 7192


Problem Description
Network flow is a well-known difficult problem for ACMers. Given a graph, your task is to find out the maximum flow for the weighted directed graph.
 

Input
The first line of input contains an integer T, denoting the number of test cases.
For each test case, the first line contains two integers N and M, denoting the number of vertexes and edges in the graph. (2 <= N <= 15, 0 <= M <= 1000)
Next M lines, each line contains three integers X, Y and C, there is an edge from X to Y and the capacity of it is C. (1 <= X, Y <= N, 1 <= C <= 1000)
 

Output
For each test cases, you should output the maximum flow from source 1 to sink N.
 

Sample Input
23 21 2 12 3 13 31 2 12 3 11 3 1
 

Sample Output
Case 1: 1

Case 2: 2

//dinic模板,静态邻接表实现建图#include<cstdio>#include<iostream>#include<cstring>#include<vector>#include<queue>using namespace std;const int mn=110,mm=2200;struct Edge{    int to,cap,next;}edges[mm];int n,m,s,t,tot;int d[mn],cur[mn],head[mn];//bool vis[mn];用d[s]=1把这个空间给省了 void add(int u,int v,int cap){    edges[tot].to=v;    edges[tot].cap=cap;    edges[tot].next=head[u];    head[u]=tot++;        edges[tot].to=u;    edges[tot].cap=0;    edges[tot].next=head[v];    head[v]=tot++;}bool bfs(){    memset(d,false,sizeof(d));    queue<int> q;    q.push(s);    d[s]=1;    while(q.size())    {        int x=q.front();q.pop();        for(int i=head[x];~i;i=edges[i].next)        {            Edge& e=edges[i];            if(!d[e.to]&e.cap>0)            {                d[e.to]=d[x]+1;                q.push(e.to);            }        }    }    return d[t]!=0;}int dfs(int x,int a){    if(x==t||a==0) return a;    int flow=0,f;    for(int& i=cur[x];i!=-1;i=edges[i].next)    {        Edge& e=edges[i];        if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap)))>0)        {            e.cap-=f;            edges[i^1].cap+=f;            flow+=f;            a-=f;            if(a==0) break;        }    }    return flow;}int dinic(){    int flow=0;    while(bfs())    {        memcpy(cur,head,sizeof(head));        flow+=dfs(s,0x3f3f3f3f);    }    return flow;}int main(){    int T;    cin>>T;    for(int kase=1;kase<=T;++kase)    {        cin>>n>>m;        int u,v,w;        tot=0;        memset(head,-1,sizeof(head));        for(int i=0;i<m;++i)        {            cin>>u>>v>>w;            add(u,v,w);        }        s=1,t=n;        cout<<"Case "<<kase<<": "<<dinic()<<endl;     }    return 0;}


//dinic模板,从宏观上讲,如果能用bfs构造层次图,就用阻塞流(dfs)来增广 //参考p360,vector实现邻接表 #include<cstdio>#include<iostream>#include<cstring>#include<vector>#include<queue>using namespace std;const int mn=110,mm=2200;//此题数据好水,其他数据修改其值即可 struct Edge{    int to,cap;//cap为剩余容量};int n,m,s,t;int d[mn];//从起点到i的距离 int cur[mn];//当前弧下标bool vis[mn];//bfs使用vector<int> g[mn];//邻接表,g[i][j]表示结点i的第j条边在e数组中的序号vector<Edge> edges;//边表,edges[e]和edges[e^1]互为反向弧void add(int u,int v,int cap){    //同时适用于稠密图和稀疏图,并且支持重边,如果遇到重边,就相当于再加了一条边     edges.push_back((Edge){v,cap});//这两行代码在有些编译器上会报错     edges.push_back((Edge){u,0});    int m=edges.size();    g[u].push_back(m-2);    g[v].push_back(m-1);}bool bfs(){    memset(vis,false,sizeof(vis));    queue<int> q;    q.push(s);    d[s]=0;    vis[s]=true;    while(q.size())    {        int x=q.front();q.pop();        for(int i=0;i<g[x].size();++i)        {            Edge& e=edges[g[x][i]];            if(!vis[e.to]&&e.cap>0)            {                vis[e.to]=true;                d[e.to]=d[x]+1;                q.push(e.to);            }        }    }    return vis[t];}int dfs(int x,int a){    if(x==t||a==0) return a;    int flow=0,f;    for(int& i=cur[x];i<g[x].size();++i)    //保存每个结点正在考虑的弧cur[x],以避免重复计算,注意那个引用    /*    用cur[x]数组的目的:仔细想了下,只有通过cur[x]这个弧后面的路径不能增广的时候,    cur[x]才会自加,这样就非常的巧妙了     */     {        Edge& e=edges[g[x][i]];        if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap)))>0)        {            e.cap-=f;            edges[g[x][i]^1].cap+=f;//反向弧,那个^1的位置需要注意             flow+=f;            a-=f;            if(a==0) break;        }    }    return flow;}int dinic(){    int flow=0;    while(bfs())    {        memset(cur,0,sizeof(cur));        flow+=dfs(s,0x3f3f3f3f);    }    return flow;}int main(){    int T;    cin>>T;    for(int kase=1;kase<=T;++kase)    {        cin>>n>>m;        int u,v,w;        edges.clear();        for(int i=0;i<n+1;i++) g[i].clear();//这个地方小心源点和汇点,点数可能增加         for(int i=0;i<m;++i)        {            cin>>u>>v>>w;            add(u,v,w);        }        s=1,t=n;        cout<<"Case "<<kase<<": "<<dinic()<<endl;     }    return 0;}


//最大流入门,Ford-Fulkerson算法 #include<iostream>#include<cstdio>#include<queue>#include<cstring>using namespace std;const int mn=20;int n,m,pre[mn],cost[mn][mn];bool bfs(){//bfs找增广路queue<int> q;q.push(1);int vis[mn]={0};vis[1]=1;//这句也别忘了 while(!q.empty()){int k=q.front();q.pop();for(int i=1;i<=n;i++)if(!vis[i]&&cost[k][i]>0){pre[i]=k;if(i==n) return true;q.push(i);vis[i]=1;}}return false;}int maxflow(){int ans=0;while(bfs()){int mi=0x3f3f3f3f,i=n;while(i!=1){mi=min(mi,cost[pre[i]][i]);i=pre[i];}ans+=mi;i=n;while(i!=1){int t=pre[i];cost[t][i]-=mi;cost[i][t]+=mi;//这句别忘了 i=t;}}return ans;}int main(){int u,v,w,T;cin>>T;for(int i=1;i<=T;i++){memset(cost,0,sizeof(cost));cin>>n>>m;for(int i=1;i<=m;i++){cin>>u>>v>>w;cost[u][v]+=w;//这个地方我能说巨坑吗 }cout<<"Case "<<i<<": "<<maxflow()<<endl;}return 0;}

ISAP算法。 第二种算法没有正式的名称, 首次出现于AhujaOrlin
经典教材《
Network Flows: Theory, Algorithms and Applications》 中, 作者
称它是一种
改进版的SAPImproved SAP, ISAP 以后补充

1 0
原创粉丝点击