hust1342(流量有上下界的最小流)

来源:互联网 发布:php url补全函数 编辑:程序博客网 时间:2024/05/16 05:49

题意:

给出一个有向无环图(DAG),我们规定有一些边是必须走的,当走到一个出度是0的点时,我们可以瞬移到任何一个我们想去的点,自选起点,走遍所有的必须走的边,使得瞬移次数最少。


思路:

这类题完全没做过啊,赛后问了过了这道题的同学,才知道这么个东西,具体怎么建图模板里都告诉了,红书上就有。


代码:

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#include<cmath>#include<cstdlib>#include<climits>#include<queue>#include<stack>#include<set>#include<string>#include<vector>using namespace std;const int maxn = 510, maxm = maxn * maxn;const int inf = 1000000000;class MaxFlow//一个挺快的模板,比一般的MaxFlow快,我也不知道为什么。。。{private:    int next[maxm*2];    int num[maxm*2];    int a[maxn*2];    int row_sum[maxn];    int col_sum[maxn];    int n , m, K;    int d[maxn*2], st[maxn*2], cod[maxn][maxn];    int h[maxn*2], vh[maxn*2];    bool don[maxm*2],in[maxn*2];    int dfs(int, int);    bool visit(int, int);public:    int T;    int r[maxm*2];    MaxFlow() {}    int Addedge(int, int, int);    int Run();    bool FindCircle();    void Init(int m)    {        memset(a, 0, sizeof(a));        tt = 1;        T = m;    }    int tt;    ~MaxFlow() {}} mf;int MaxFlow::Addedge(int x,int y,int rr){    next[++tt]=a[x];    num[tt]=y;    r[tt]=rr;    a[x]=tt;    next[++tt]=a[y];    num[tt]=x;    r[tt]=0;    a[y]=tt;    return tt;}int MaxFlow::dfs(int x,int y){    if (x==T) return y;    int sig=st[x],minh=T+1;    do    {        if (r[st[x]])        {            if (h[num[st[x]]]+1==h[x])            {                int k=dfs(num[st[x]],min(y,r[st[x]]));                if (k)                {                    r[st[x]]-=k;                    r[st[x]^1]+=k;                    return k;                }            }            minh=min(minh,h[num[st[x]]]+1);            if (h[0]>T) return 0;        }        st[x]=next[st[x]];        if (st[x]==0) st[x]=a[x];    }    while (sig!=st[x]);    if (vh[h[x]]--==0) h[0]=T+1;    vh[h[x]=minh]++;    return 0;}int MaxFlow::Run(){    for (int i=0; i<=T; i++) h[i]=vh[i]=0;    for (int i=0; i<=T; i++) st[i]=a[i];    vh[0]=T+1;    int ret=0;    while (h[0]<=T) ret+=dfs(0,K+1);    return ret;}bool MaxFlow::visit(int x,int ed){    if (don[ed])        return in[x];    don[ed]=true;    in[x]=true;    for (int p=a[x]; p; p=next[p])    {        if (r[p] && (ed^p)!=1)            if (visit(num[p],p)) return true;    }    in[x]=false;    return false;}bool MaxFlow::FindCircle(){    for (int i=0; i<=T; i++) in[i]=false;    for (int i=1; i<=tt; i++) don[i]=false;    for (int i=2; i<=tt; i++)    {        if (r[i] && !don[i])        {            in[num[i^1]]=true;            if (visit(num[i],i)) return true;            in[num[i^1]]=false;        }    }    return false;}int cnt[maxn]; //节点的度int main(){    int t;scanf("%d",&t);int cas=1;while(t--)    {        int n, m;        scanf("%d%d", &n, &m);        int ss = 0, tt = n+3;//源点和汇点        int s = n + 2, t = n+1;//附加源点和附加汇点        mf.Init(tt);//注意模板的坑,此模板的源点一定是0,不能自己设定,汇点就是tt        for (int i = 1; i <= n; i++)        {            mf.Addedge(s, i, inf);            mf.Addedge(i, t, inf);        }        memset(cnt, 0, sizeof cnt);        int sum = 0;        while (m--)        {            int u, v, w;            scanf("%d%d%d", &u, &v, &w);            if (w)            {                sum++;                cnt[u]--;                cnt[v]++;            }            mf.Addedge(u, v, inf);        }        for (int i = 1; i <= n; i++)        {            if (cnt[i] < 0)                mf.Addedge(i, tt, -cnt[i]);            else                mf.Addedge(ss, i, cnt[i]);        }        mf.Run();        int fuck = mf.Addedge(t, s, sum);        mf.Run();        printf("Case #%d: %d\n", cas++, sum - mf.r[fuck^1]);//为什么异或1,因为这个模板的返回值返回的是反向边的流量,所以^1了才是正向边的流量    }    return 0;}


0 0
原创粉丝点击