HIT暑期集训 网络流

最大流模板(修改版)

/*网络流中的最大流问题
即,给出一个图,图中每条边有一个容量,图中有两点分别为源点和汇点 
在每条边流量不超过其容量的情况下,求解从原点开始能流到汇点的最大流量
dinic算法是一种基于增广路思想求解最大流的算法,其基本步骤为:
1、在图中找到一条从源点到汇点的路径,
使路径上每条边的残余流量re大于零,称这条路径为增广路。
2、取该路径上的最小re,记为re_min,并将答案max_flow加上re_min。
将这条路径上所有边的re都减去re_min,他们的反向边都加上re_min。 
不停进行以上两个步骤直至图中没有增广路,最后得到的max_flow就是最大流。
下面是应用dinic算法求解最大流的代码。 
*/ 
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#define maxn 10005
#define maxm 100005
using namespace std; 
const int inf=1<<30;
int num,lst[maxn],cur[maxn],dep[maxn];
int s,t,n,m;
queue<int>q;
struct in
{
    int to,nxt,re;
}e[maxm];
void add(int x,int y,int z)//邻接表建图 
{
    e[++num].to=y;
    e[num].nxt=lst[x];
    lst[x]=num;
    e[num].re=z;
}
void clear()
{
    num=-1;//从0开始为边编号 
    memset(lst,-1,sizeof(lst));
}
int bfs()//广搜,进行图分层 
{
    int i,u,v;
    while (!q.empty()) q.pop(); //清空队列 
    memset(dep,-1,sizeof(dep));
    dep[s]=0;
    q.push(s);
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        for(i=lst[u];i!=-1;i=e[i].nxt)
        {
            v=e[i].to;
            if (e[i].re && dep[v]==-1)//如果该节点之前没有被搜索到并且不是反向边 
            {
                dep[v]=dep[u]+1;//更新该节点深度 
                q.push(v);//将该节点加入队列 
            }
        }
    }
    return dep[t]!=-1;//没有搜索到汇点就不存在增广路 
}
int dfs(int u,int flow)//寻找增广路并返回其流量 
{
    //x表示当前节点,flow表示当前流到x的残量
    if (u==t || !flow) return flow;
    int i,v,res,used=0;//used表示u节点总共流出的流量 
    for (i=cur[u];i!=-1;i=e[i].nxt)
    {
        v=e[i].to;
        cur[u]=i;//当前弧优化  
        if (dep[v]==dep[u]+1 && e[i].re)//v为u的下一层,且当前边有残量>0 
        {
            res=dfs(v,min(flow,e[i].re));//res表示当前边流出的流量 
            if (res)
            {
                used+=res;
                flow-=res;
                e[i].re-=res;
                e[i^1].re+=res;//i^1是i的反向边  
                if (!flow) return used;//流入当前点的流量流完了,退出 
            } 
        }
    }
    if (flow) dep[u]=-1;//优化,流到u的流量会有冗余,这一轮dfs中就再也用不到u了(u已经无法流出更多流量) 
    return used;
}
int dinic()//不停寻找增广路并更新答案,直至图中不存在增广路 
{
    int i,maxflow=0;
    while (bfs())
    {
        for (i=0;i<=max(n,t);i++) cur[i]=lst[i];//当前弧优化,重置cur 
        maxflow+=dfs(s,inf);//加入寻找到的增广路的流量 
    }
    return maxflow;
}
int main()
{
    int u,v,w,i;
    clear();
    scanf("%d%d%d%d",&n,&m,&s,&t);//n节点数,m边数,s源点,t汇点 
    for(i=1;i<=m;i++)//读入m条边 
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,0);//反向边 
    }
    printf("%d\n",dinic());
    return 0;
}
dinic最大流模板,带注释
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#define maxn 10005
#define maxm 100005
using namespace std; 
const int inf=1<<30;
int num,lst[maxn],cur[maxn],dep[maxn];
int s,t,n,m;
queue<int>q;
struct in
{
    int to,nxt,re;
}e[maxm];
void add(int x,int y,int z)
{
    e[++num].to=y;
    e[num].nxt=lst[x];
    lst[x]=num;
    e[num].re=z;
}
void clear()
{
    num=-1;
    memset(lst,-1,sizeof(lst));
}
int bfs()
{
    int i,u,v;
    while (!q.empty()) q.pop();
    memset(dep,-1,sizeof(dep));
    dep[s]=0;
    q.push(s);
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        for(i=lst[u];i!=-1;i=e[i].nxt)
        {
            v=e[i].to;
            if (e[i].re && dep[v]==-1)
            {
                dep[v]=dep[u]+1;
                q.push(v);
            }
        }
    }
    return dep[t]!=-1;
}
int dfs(int u,int flow)
{
    if (u==t || !flow) return flow;
    int i,v,res,used=0;
    for (i=cur[u];i!=-1;i=e[i].nxt)
    {
        v=e[i].to;
        cur[u]=i;
        if (dep[v]==dep[u]+1 && e[i].re)
        {
            res=dfs(v,min(flow,e[i].re));
            if (res)
            {
                used+=res;
                flow-=res;
                e[i].re-=res;
                e[i^1].re+=res;
                if (!flow) return used;
            } 
        }
    }
    if (flow) dep[u]=-1; 
    return used;
}
int dinic()
{
    int i,maxflow=0;
    while (bfs())
    {
        for (i=0;i<=max(n,t);i++) cur[i]=lst[i];
        maxflow+=dfs(s,inf);
    }
    return maxflow;
}
int main()
{
    int u,v,w,i;
    clear();
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);
        add(v,u,0); 
    }
    printf("%d\n",dinic());
    return 0;
}
dinic最大流模板,无注释

最大流最小费模板(修改spfa函数中的赋初值dis[i]=-inf与if (dis[v]<dis[u]+e[i].w)就可变为最大费用最大流。)

#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#define maxn 10000
#define maxm 40000
using namespace std; 
const int inf=1<<30;
int num,lst[maxn];
int pre[maxn],vis[maxn],flow[maxn],dis[maxn],from[maxn];
int tot1,tot2,q1[maxn][2],q2[maxn][2];
int s,t,n,m,lim;
queue<int>q;
struct in
{
    int to,nxt,re,w;
}e[maxm];
void add(int x,int y,int z,int w)
{
    e[++num].to=y;e[num].nxt=lst[x];lst[x]=num;e[num].re=z;e[num].w=w;
}
void clear()
{
    num=-1;
    memset(lst,-1,sizeof(lst));
}
int spfa()
{
    int i,u,v;
    while (!q.empty()) q.pop();
    for (i=1;i<=t;++i) 
    {
        pre[i]=-1;
        from[i]=-1;
        dis[i]=inf;
        vis[i]=0;
    }
    q.push(s);
    dis[s]=0;
    flow[s]=inf;
    vis[s]=1;
    while (!q.empty())
    {
        u=q.front();
        q.pop();
        vis[u]=0;
        for (i=lst[u];i!=-1;i=e[i].nxt)
        {
            v=e[i].to;
            if (!e[i].re) continue;
            if (dis[v]>dis[u]+e[i].w)
            {
                dis[v]=dis[u]+e[i].w;
                flow[v]=min(e[i].re,flow[u]);
                pre[v]=i;
                from[v]=u;
                if (!vis[v]) 
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        }
    }
    return pre[t]!=-1;
}
int mfmv()
{
    int mincost=0,maxflow=0,v;
    while (spfa())
    {
        mincost+=flow[t]*dis[t];
        maxflow+=flow[t];
        v=t;
        while (v!=s)
        {
            e[pre[v]].re-=flow[t];
            e[pre[v]^1].re+=flow[t];
            v=from[v];
        }
    }
    return mincost;
}
int main()
{
    int i,x,y,z,w;
    clear();
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for (i=1;i<=m;i++)
    {
        scanf("%d%d%d%d",&x,&y,&z,&w);
        add(x,y,z,w);
        add(y,x,0,-w);
    }
    printf("%d\n",mfmv());
    return 0;
} 
mfmv模板,spfa,无注释

B    HDU 3572

建图,将每一天j与源点s连边add(s,j,m),每个任务i与汇点t连边add(i,t,p),每个任务i与可以做这个任务的每一天j连边add(j,i,1)。然后求最大流,如果最大流等于所有任务所需的天数p之和,就YES,否则NO。

昨天折腾一晚上,不停TLE,然后加了一个优化(就是那个if (flow) dep[u]=-1的优化)过了。。行吧,修改了一下dinic模板。。

#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
#define maxn 1010
#define maxm 500005
#define inf 0x3f3f3f3f
using namespace std; 
int num,lst[maxn],dep[maxn],mark[maxn],cur[maxn];
int s,t,n;
queue<int>q;
struct in
{
    int to,nxt,re;
}e[maxm];
void add(int x,int y,int z)
{
    e[++num].to=y;e[num].nxt=lst[x];lst[x]=num;e[num].re=z;
    e[++num].to=x;e[num].nxt=lst[y];lst[y]=num;e[num].re=0;
}
void clear()
{
    num=-1;//从0开始为边编号 
    memset(lst,-1,sizeof(lst));
}
int bfs()//广搜,进行图分层 
{
    int i,u,v;
    while (!q.empty()) q.pop(); //清空队列 
    memset(dep,-1,sizeof(dep));
    dep[s]=0;
    q.push(s);
    while(!q.empty())
    {
        u=q.front();
        q.pop();
        for(i=lst[u];i!=-1;i=e[i].nxt)
        {
            v=e[i].to;
            if (e[i].re && dep[v]==-1)//如果该节点之前没有被搜索到并且不是反向边 
            {
                dep[v]=dep[u]+1;//更新该节点深度 
                q.push(v);//将该节点加入队列 
            }
        }
    }
    return dep[t]!=-1;//没有搜索到汇点就不存在增广路 
}
int dfs(int u,int flow)//寻找增广路并返回其流量 
{
    //x表示当前节点,flow表示当前流到x的残量
    if (u==t || !flow) return flow;
    int i,v,res,used=0;//used表示u节点总共流出的流量 
    for (i=cur[u];i!=-1;i=e[i].nxt)
    {
        v=e[i].to;
        cur[u]=i;//当前弧优化  
        if (dep[v]==dep[u]+1 && e[i].re)//v为u的下一层,且当前边有残量>0 
        {
            res=dfs(v,min(flow,e[i].re));//res表示当前边流出的流量 
            if (res)
            {
                used+=res;
                flow-=res;
                e[i].re-=res;
                e[i^1].re+=res;//i^1是i的反向边  
                if (!flow) return used;//流入当前点的流量流完了,退出 
            } 
        }
    }
    if (flow) dep[u]=-1;//优化,流到u的流量会有冗余,这一轮dfs中就再也用不到u了(u已经无法流出更多流量) 
    return used;
}
int dinic()//不停寻找增广路并更新答案,直至图中不存在增广路 
{
    int i,maxflow=0;
    while (bfs())
    {
        for (i=0;i<=max(n,t);i++) cur[i]=lst[i];//当前弧优化,重置cur 
        maxflow+=dfs(s,inf);//加入寻找到的增广路的流量 
    }
    return maxflow;
}
int main()
{
    int i,j,k,x,y,z,T,m,sum,note=1;
    int maxflow,flow;
    scanf("%d",&T);
    for (k=1;k<=T;k++)
    {
        scanf("%d%d",&n,&m);
        s=0;t=500+n+1;
        clear();
        sum=0;
        memset(mark,0,sizeof(mark));
        for (i=1;i<=n;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            for (j=y;j<=z;j++)
            {
                mark[j]=1;
                add(j,i+500,1);
            }
            add(i+500,t,x);
            sum+=x;
        }
        for (i=1;i<=500;i++)
        {
            if (!mark[i]) continue;
            add(s,i,m);
        }
        if (dinic()==sum) printf("Case %d: Yes\n\n",k);
        else printf("Case %d: No\n\n",k);
    }
    return 0;
 }
View Code

 

posted @ 2020-08-14 01:45  lsy_kk  阅读(146)  评论(0编辑  收藏  举报