[CQOI2014]危桥 指定的2个起点和2个终点的网络流

题目

([CQOI2014]危桥)https://ac.nowcoder.com/acm/problem/19931

题目描述

Alice和Bob居住在一个由N座岛屿组成的国家,岛屿被编号为0到N-1。某些岛屿之间有桥相连,桥上的道路是双向的,但一次只能供一人通行。其中一些桥由于年久失修成为危桥,最多只能通行两次。Alice希望在岛屿a1和a2之间往返an次(从a1到a2再从a2到a1算一次往返)。同时,Bob希望在岛屿b1和b2之间往返bn次。这个过程中,所有危桥最多通行两次,其余的桥可以无限次通行。请问Alice和Bob能完成他们的愿望吗?
输入描述:
本题有多组测试数据。 每组数据第一行包含7个空格隔开的整数,分别为N、a1、a2、an、b1、b2、bn。
接下来是一个N行N列的对称矩阵,由大写字母组成。矩阵的i行j列描述编号i一1和j-l的岛屿间的连接情况,若为“O”则表示有危桥相连;为“N”表示有普通的桥相连;为“X”表示没有桥相连。
输出描述:
对于每组测试数据输出一行,如果他们都能完成愿望输出“Yes”,否则输出“No”。

示例1

输入
4 0 1 1 2 3 1
XOXX
OXOX
XOXO
XXOX
4 0 2 1 1 3 2
XNXO
NXOX
XOXO
OXOX
输出
Yes
No

说明

数据范围
4<=N<50
O<=a1, a2, b1, b2<=N-1
1 <=an,bn<=50

思路

因为经过次数是来回,所以我们得到一个很简单的建模:
S向a1, b1分别连一条容量为an, bn的边。
a2, b2分别向T连一条an, bn的边。
危桥之间连接容量为1的边。普通边连接inf的边。
但是一个问题。怎么确保a1的流量全部是流向a2的。
如下图:

u-v是所有a1-b2和b1-a2的链之间的流量。这样也可以得到最大流但是并不满足题目要求。除非u->v的考研流x+y的流量。
那么我们怎么确定u->v能不能留x+y的流量。我们交换有b1和b2的位置。如果还能最大流,所有的流量一定经过u-v这条边。
那么就说明满足条件了。

而且如果之前本来就是a1->a2,b1->b2那么交换b1, b2并不会影响结果。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#include<string>
#include<iostream>
#define INF 1e9
using namespace std;
const int maxn =1000+10;

struct Edge {
    int from,to,cap,flow;
    Edge() {}
    Edge(int f,int t,int c,int fl):from(f),to(t),cap(c),flow(fl) {}
};

struct Dinic {
    int n,m,s,t;
    vector<Edge> edges;
    vector<int> G[maxn];
    int cur[maxn];
    int d[maxn];
    bool vis[maxn];

    void init(int n,int s,int t) {
        this->n=n, this->s=s, this->t=t;
        edges.clear();
        for(int i=0; i<n; i++)
            G[i].clear();
    }

    void AddEdge(int from,int to,int cap) {
        edges.push_back( Edge(from,to,cap,0) );
        edges.push_back( Edge(to,from,0,0) );
        m = edges.size();
        G[from].push_back(m-2);
        G[to].push_back(m-1);
    }

    bool BFS() {
        queue<int> Q;
        Q.push(s);
        memset(vis,0,sizeof(vis));
        d[s]=0;
        vis[s]=true;
        while(!Q.empty()) {
            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>e.flow) {
                    d[e.to]=1+d[x];
                    vis[e.to]=true;
                    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[e.to]==d[x]+1 && (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 max_flow() {
        int ans=0;
        while(BFS()) {
            memset(cur,0,sizeof(cur));
            ans += DFS(s,INF);
        }
        return ans;
    }
} DC;

char s[55][55];
int main() {
    int n, a1, a2, an, b1, b2, bn;
    while(~scanf("%d%d%d%d%d%d%d", &n, &a1, &a2, &an, &b1, &b2, &bn)) {
        a1++, a2++, b1++, b2++;
        int S=0, T=n+1;
        DC.init(n+5, S, T);
        for(int i=1; i<=n; i++) {
            scanf("%s", s[i]+1);
            for(int k=1; k<=n; k++) {
                if(s[i][k]=='O') {
                    DC.AddEdge(i, k, 1);
                }
                if(s[i][k]=='N') {
                    DC.AddEdge(i, k, INF);
                }
            }
        }
        DC.AddEdge(S, a1, an);
        DC.AddEdge(S, b1, bn);
        DC.AddEdge(a2, T, an);
        DC.AddEdge(b2, T, bn);
        if(DC.max_flow()!=an+bn) {
            printf("No\n");
            continue;
        }
        DC.init(n+5, S, T);
        for(int i=1; i<=n; i++) {
            for(int k=1; k<=n; k++) {
                if(s[i][k]=='O') {
                    DC.AddEdge(i, k, 1);
                }
                if(s[i][k]=='N') {
                    DC.AddEdge(i, k, INF);
                }
            }
        }
        DC.AddEdge(S, a1, an);
        DC.AddEdge(S, b2, bn);
        DC.AddEdge(a2, T, an);
        DC.AddEdge(b1, T, bn);
        if(DC.max_flow()!=an+bn) {
            printf("No\n");
            continue;
        }
        printf("Yes\n");
    }

    return 0;
}

posted @   liweihang  阅读(120)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
Live2D
欢迎阅读『[CQOI2014]危桥 指定的2个起点和2个终点的网络流』
点击右上角即可分享
微信分享提示