uva11248 Frequency Hopping

本文探讨了在有向网络中,如何通过修改单个弧的容量,以达到存在特定流量流的目标。首先计算最大流,若不满足条件,则通过调整限制最大流的弧的容量,并再次求解最大流,确保最终流量至少等于目标流量。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给定一个有向网络, 每条边均有一个容量。问是否存在一个从点1到点N,流量为C的流。如果不存在, 是否可以恰好修改一条弧饿容量, 使得存在这样的流。


先求最大流mf,如果mf >= C,则直接输出possible

若暂时不存在,那么便是最小割中的边限制了增广路的产生,可以通过修改其中的弧容量(设为C足矣),再求最大流,此时若大于C则此弧可以

不过这样会超时

其实最大流在此题中没有意义,所以当流量>=C的时候就可以停止增广了

还有就是保留第一次增广后的各条边中的流量,以后在此基础上进行增广即可


#include <cstdio>
#include <ctime>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <string>
#include <set>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
//LOOP
#define FF(i, a, b) for(int i = (a); i < (b); ++i)
#define FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FED(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
//STL
#define PB push_back
#define ALL(c) (c).begin(), (c).end()
//INPUT
#define RI(n) scanf("%d", &n)
#define RII(n, m) scanf("%d%d", &n, &m)
#define RIII(n, m, k) scanf("%d%d%d", &n, &m, &k)
//OUTPUT
#define WI(n) printf("%d\n", n)
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> VI;
const int INF = 100000000;
const double eps = 1e-10;
const int maxn = 110;
/////Dinic算法//////
struct Edge{
    int from, to, cap, flow;
    bool operator < (const Edge& e) const{
        return (from < e.from || (from == e.from && to < e.to));
    }
};
vector<Edge> edges;
VI G[maxn];
int n, m, s, t, C;
bool vis[maxn];
int d[maxn], cur[maxn];

void add(int from, int to, int cap)
{
    edges.PB((Edge){from, to, cap, 0});
    edges.PB((Edge){to, from, 0, 0});
    int sz = edges.size();
    G[from].PB(sz - 2);
    G[to].PB(sz - 1);
}

bool bfs()
{
    CLR(vis, 0);
    queue<int> Q;
    Q.push(s);
    d[s] = 0;
    vis[s] = 1;
    while (!Q.empty())
    {
        int x = Q.front(); Q.pop();
        REP(i, G[x].size())
        {
            Edge& e = edges[G[x][i]];
            if (!vis[e.to] && e.cap > e.flow)
            {
                vis[e.to] = 1;
                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++)
    {
        Edge& e = edges[G[x][i]];
        if (d[x] + 1 == d[e.to] && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0)
        {
            e.flow += f;
            edges[G[x][i] ^ 1].flow -= f;
            flow += f;
            a -= f;
            if (a == 0) break;
        }
    }
    return flow;
}

int maxflow()
{
    int flow = 0;
    while (bfs())
    {
        CLR(cur, 0);
        flow += dfs(s, INF);
        if (flow >= C)
            break;
    }
    return flow;
}

void init()
{
    FE(i, 0, n + 1)
        G[i].clear();
    edges.clear();
    s = 1, t = n;
}

VI mincut;
VI last;        //  保存第一次最大流中各边的流量,之后在此基础上增广

void solve()
{
    int mf = maxflow();
    if (mf >= C)
    {
        puts("possible");
        return;
    }
    mincut.clear(), last.clear();
    bfs();
    m = edges.size();
    REP(i, m)
    {
        int u = edges[i].from, v = edges[i].to, c = edges[i].cap;
        if (vis[u] && !vis[v] && c > 0)
            mincut.PB(i);
    }
    int sz = mincut.size();
    vector<Edge> ans;
    REP(j, m)   last.PB(edges[j].flow);
    REP(i, sz)
    {
        REP(j, m)   edges[j].flow = last[j];
        int oc = edges[mincut[i]].cap;
        edges[mincut[i]].cap = C;
        if (mf + maxflow() >= C)  ans.PB(edges[mincut[i]]);
        edges[mincut[i]].cap = oc;
    }
    sort(ALL(ans));
    if (ans.size() > 0)
    {
        printf("possible option:");
        REP(i, ans.size())
        {
            if (i)  printf(",");
            printf("(%d,%d)", ans[i].from, ans[i].to);
        }
        puts("");
    }
    else
        puts("not possible");
}

int main()
{
    int kase = 0;
    while (~RIII(n, m, C), n || m || C)
    {
        int u, v, cap;
        init();
        REP(i, m)
        {
            RIII(u, v, cap);
            add(u, v, cap);
        }
        printf("Case %d: ", ++kase);
        solve();
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值