题解:蓝书习题·第五章·图论·网络流

图论模板

Frequency Hopping

先求一次最大流若流量不小于C则possible,否则依次把最小割里的弧容量加到C再看流量是否大于C。
蓝书上说这样会T但是事实上并没有…加上蓝书上的两个优化也不过只快了一两百ms而已。

#include<bits/stdc++.h>
using namespace std;
typedef int ll;
const ll INF=0x3f3f3f3f;
struct Graph
{
    struct Vertex
    {
        vector<int> a;
    };
    struct Edge
    {
        int from,to;
        ll cap;
        bool operator<(const Edge &e)const
        {
            return from!=e.from?
                   from<e.from:
                   to<e.to;
        }
    };
    vector<Vertex> v;
    vector<Edge> e;
    Graph(int n):v(n) {}
    void add(const Edge &ed)
    {
        v[ed.from].a.push_back(e.size());
        e.push_back(ed);
    }
};
struct ISAP:Graph
{
    ll flow;
    vector<ll> f;
    vector<int> h,cur,gap;
    ISAP(int n):Graph(n) {}
    void add(Edge ed)
    {
        Graph::add(ed);
        swap(ed.from,ed.to),ed.cap=0;
        Graph::add(ed);
    }
    ll dfs(int s,int u,int t,ll r)
    {
        if(r==0||u==t)return r;
        ll _f,_r=0;
        for(int &i=cur[u],k; i<v[u].a.size(); ++i)
            if(k=v[u].a[i],h[u]==h[e[k].to]+1)
            {
                _f=dfs(s,e[k].to,t,min(r-_r,e[k].cap-f[k]));
                f[k]+=_f,f[k^1]-=_f,_r+=_f;
                if(_r==r||h[s]>=v.size())return _r;
            }
        if(!--gap[h[u]])h[s]=v.size();
        return ++gap[++h[u]],cur[u]=0,_r;
    }
    void ask(int s,int t)
    {
        h.assign(v.size(),0);
        cur.assign(v.size(),0);
        gap.assign(v.size()+2,0);
        for(f.assign(e.size(),flow=0); h[s]<v.size();)
            flow+=dfs(s,s,t,INF);
    }
};
int main()
{
    for(int n,e,c,kase=0; scanf("%d%d%d",&n,&e,&c)&&n;)
    {
        printf("Case %d: ",++kase);
        ISAP g(n+1);
        for(ISAP::Edge ed; e--; g.add(ed))
            scanf("%d%d%d",&ed.from,&ed.to,&ed.cap);
        g.ask(1,n);
        if(g.flow>=c)
        {
            printf("possible\n");
            continue;
        }
        vector<int> vis(n+1,0),mincut;
        for(deque<int> q(1,vis[1]=1); !q.empty(); q.pop_front())
            for(int i=0,u=q.front(),k,to; i!=g.v[u].a.size(); ++i)
                if(k=g.v[u].a[i],to=g.e[k].to,
                        !vis[to]&&g.e[k].cap>g.f[k])
                    q.push_back(to),vis[to]=1;
        for(int i=0; i!=g.e.size(); ++i)
            if(vis[g.e[i].from]&&!vis[g.e[i].to]&&g.e[i].cap>0)
                mincut.push_back(i);
        vector<ISAP::Edge> ans;
        for(int i=0,tmp=c; i!=mincut.size(); ++i)
        {
            swap(tmp,g.e[mincut[i]].cap);
            g.ask(1,n);
            if(g.flow>=c)ans.push_back(g.e[mincut[i]]);
            swap(tmp,g.e[mincut[i]].cap);
        }
        if(ans.empty())
        {
            printf("not possible\n");
            continue;
        }
        printf("possible option:");
        sort(ans.begin(),ans.end());
        for(int i=0; i!=ans.size(); ++i)
            printf("(%d,%d)%c",
                   ans[i].from,ans[i].to,
                   i+1!=ans.size()?',':'\n');
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值