Codeforces Gym 100825F Transportation Delegation (最大流)

本文介绍了一种使用网络流算法解决特定匹配问题的方法。问题涉及多个州拥有工厂或原材料供应商,通过运输公司连接这些点来实现工厂与供应商的最大匹配对数。通过构建特殊的网络流图并运行最大流算法,实现了高效的求解。

题目大意:

就是现在有s个州, 每个州要么有工厂要么有原材料供应商或者什么都没有, 有的话只有一家

现在有t个运输公司分别提供运输服务

要求一个工厂只能匹配一个供应商,一个供应商只能供应一个工厂,且要满足一个运输公司只为其中一个匹配对服务(可以通过多个运输公司一起来传递来配对一个工厂和供应商)

问最大匹配对数


大致思路:

EC-final前最后一个题.....打完之后训练就结束了呢= =

表示这个题真是让我见识到了什么叫网络流不知道可不可以,先来一发T了再说...简直暴力出奇迹

可以考虑这么建图:

所有工厂和源点连一条容量为1的边, 然后供应商和汇点连一条容量为1的边

对于每一个运输公司,抽象出两个点p1, p2,连一条容量为1的边来控制公司只用一次

对于每一个该运输公司可以服务的点与p1连一条容量1的边, 与p2连一条容量1的边

于是跑一遍最大流就是答案了

这个图最坏情况下应该是1000*2+600+2个点

600*2*1000+1000+600条无向边(120W...)

然而网络流单组数据只跑了159ms.....好强大...


代码如下:

Result  :  Accepted     Memory  :  37712 KB     Time  :  156 ms

/*
 * Author: Gatevin
 * Created Time:  2015/12/11 0:11:10
 * File Name: Yukinoshita_Yukino.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<iomanip>
using namespace std;
const double eps(1e-8);
typedef long long lint;

#define maxn 2700

#define maxm 1202000

struct Edge
{
    int u, v, nex, cap;
    Edge(){}
    Edge(int _u, int _v, int _nex, int _cap)
    {
        u = _u, v = _v, nex = _nex, cap = _cap;
    }
};

Edge edge[maxm << 1];
int E;
int head[maxn];

void add_Edge(int u, int v, int c)
{
    edge[++E] = Edge(u, v, head[u], c);
    head[u] = E;
    edge[++E] = Edge(v, u, head[v], 0);
    head[v] = E;
}

int dep[maxn];

bool bfs(int start, int end)
{
    int Q[maxn];
    int l, r;
    l = r = 0;
    memset(dep, -1, sizeof(dep));
    Q[r++] = start;
    dep[start] = 0;
    while(l != r)
    {
        int u = Q[l++];
        if(l == maxn) l = 0;
        for(int i = head[u]; i + 1; i = edge[i].nex)
        {
            int v = edge[i].v;
            if(edge[i].cap > 0 && dep[v] == -1)
            {
                dep[v] = dep[u] + 1;
                Q[r++] = v;
                if(r >= maxn) r = 0;
                if(v == end) return 1;
            }
        }
    }
    return 0;
}



int dinic(int start, int end)
{
    int res = 0;
    int top;
    int cur[maxn];
    int stack[maxn];
    while(bfs(start, end))
    {
        memcpy(cur, head, sizeof(head));
        int u = start;
        top = 0;
        while(1)
        {
            if(u == end)
            {
                int min = 1e9;
                int loc;
                for(int i = 0; i < top; i++)
                    if(min > edge[stack[i]].cap)
                    {
                        min = edge[stack[i]].cap;
                        loc = i;
                    }
                for(int i = 0; i < top; i++)
                {
                    edge[stack[i]].cap -= min;
                    edge[stack[i] ^ 1].cap += min;
                }
                res += min;
                top = loc;
                u = edge[stack[top]].u;
            }
            for(int i = cur[u]; i + 1; cur[u] = i = edge[i].nex)
                if(edge[i].cap != 0 && dep[u] + 1 == dep[edge[i].v])
                    break;
            if(cur[u] != -1)
            {
                stack[top++] = cur[u];
                u = edge[cur[u]].v;
            }
            else
            {
                if(top == 0) break;
                dep[u] = -1;
                u = edge[stack[--top]].u;
            }
        }
    }
    return res;
}

map<string, int> M;

int main()
{
    ios::sync_with_stdio(0);
    E = -1;
    memset(head, -1, sizeof(head));
    int s, r, f, t;
    cin>>s>>r>>f>>t;
    string name;
    int S = 0, T = s + 2*t + 1;
    int cnt = 0;
    for(int i = 0; i < r; i++)
    {
        cin>>name;
        if(M.count(name) == 0)
        {
            M[name] = ++cnt;
            add_Edge(S, cnt, 1);
        }
    }
    for(int i = r + 1; i <= r + f; i++)
    {
        cin>>name;
        if(M.count(name) == 0)
        {
            M[name] = ++cnt;
            add_Edge(cnt, T, 1);
        }
    }
    for(int i = 1; i <= t; i++)
    {
        int x;
        cin>>x;
        int point1 = ++cnt, point2 = ++cnt;
        add_Edge(point1, point2, 1);
        while(x--)
        {
            cin>>name;
            if(M.count(name) == 0)
                M[name] = ++cnt;
            int num = M[name];
            add_Edge(num, point1, 1);
            add_Edge(point2, num, 1);
        }
    }
    cout<<dinic(S, T)<<endl;
    return 0;
}



Codeforces Gym 101630 是一场编程竞赛,通常包含多个算法挑战问题。这些问题往往涉及数据结构、算法设计、数学建模等多个方面,旨在测试参赛者的编程能力和解决问题的能力。 以下是一些可能出现在 Codeforces Gym 101630 中的题目类型及解决方案概述: ### 题目类型 1. **动态规划(DP)** 动态规划是编程竞赛中常见的题型之一。问题通常要求找到某种最优解,例如最小路径和、最长递增子序列等。解决这类问题的关键在于状态定义和转移方程的设计[^1]。 2. **图论** 图论问题包括最短路径、最小生成树、网络流等。例如,Dijkstra 算法用于求解单源最短路径问题,而 Kruskal 或 Prim 算法则常用于最小生成树问题[^1]。 3. **字符串处理** 字符串问题可能涉及模式匹配、后缀数组、自动机等高级技巧。KMP 算法和 Trie 树是解决此类问题的常用工具[^1]。 4. **数论与组合数学** 这类问题通常需要对质数、模运算、排列组合等有深入的理解。例如,快速幂算法可以用来高效计算大数的模幂运算[^1]。 5. **几何** 几何问题可能涉及点、线、多边形的计算,如判断点是否在多边形内部、计算两个圆的交点等。向量运算和坐标变换是解决几何问题的基础[^1]。 ### 解决方案示例 #### 示例问题:动态规划 - 最长递增子序列 ```python def longest_increasing_subsequence(nums): if not nums: return 0 dp = [1] * len(nums) for i in range(len(nums)): for j in range(i): if nums[i] > nums[j]: dp[i] = max(dp[i], dp[j] + 1) return max(dp) # 示例输入 nums = [10, 9, 2, 5, 3, 7, 101, 18] print(longest_increasing_subsequence(nums)) # 输出: 4 ``` #### 示例问题:图论 - Dijkstra 算法 ```python import heapq def dijkstra(graph, start): distances = {node: float('infinity') for node in graph} distances[start] = 0 priority_queue = [(0, start)] while priority_queue: current_distance, current_node = heapq.heappop(priority_queue) if current_distance > distances[current_node]: continue for neighbor, weight in graph[current_node].items(): distance = current_distance + weight if distance < distances[neighbor]: distances[neighbor] = distance heapq.heappush(priority_queue, (distance, neighbor)) return distances # 示例输入 graph = { 'A': {'B': 1, 'C': 4}, 'B': {'A': 1, 'C': 2, 'D': 5}, 'C': {'A': 4, 'B': 2, 'D': 1}, 'D': {'B': 5, 'C': 1} } start = 'A' print(dijkstra(graph, start)) # 输出: {'A': 0, 'B': 1, 'C': 3, 'D': 4} ``` #### 示例问题:字符串处理 - KMP 算法 ```python def kmp_failure_function(pattern): m = len(pattern) lps = [0] * m length = 0 # length of the previous longest prefix suffix i = 1 while i < m: if pattern[i] == pattern[length]: length += 1 lps[i] = length i += 1 else: if length != 0: length = lps[length - 1] else: lps[i] = 0 i += 1 return lps def kmp_search(text, pattern): n = len(text) m = len(pattern) lps = kmp_failure_function(pattern) i = 0 # index for text j = 0 # index for pattern while i < n: if pattern[j] == text[i]: i += 1 j += 1 if j == m: print("Pattern found at index", i - j) j = lps[j - 1] elif i < n and pattern[j] != text[i]: if j != 0: j = lps[j - 1] else: i += 1 # 示例输入 text = "ABABDABACDABABCABAB" pattern = "ABABCABAB" kmp_search(text, pattern) # 输出: Pattern found at index 10 ``` ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值