Gym-101981I Magic Potion(二分图/网络流)

本文深入探讨了Gym-101981I魔药问题,通过使用二分图和网络流算法解决英雄与怪兽的战斗策略。介绍了使用匈牙利算法和网络流中的最大流算法来确定在有限药剂条件下,英雄们能够击败的最大怪兽数量。

Gym-101981I Magic Potion(二分图/网络流)

题意

n个英雄m个怪,每个英雄只能打 m i m_i mi种怪中的一个,磕了药(且每个英雄最多磕一瓶)可以额外打死一头怪,现在有k瓶药,问最多打死多少只怪。

思路

和阿忠哥一看,匈牙利直接莽两遍不就有了,第一遍匹配没有嗑药打死几个。第二遍把第一遍打死了的剔除,再匹配磕了药打死几个(最多多打死k个)。但是wa on test7,gym和普通CF不一样我还看不到数据,气死。

但是我咨询了分别用匈牙利和网络流两种办法过了这题的宁宁姐和凉凉,宁宁表示匈牙利需要排个序才能过,不然第一遍的最优结果可能并不能导致第二遍最优。凉凉说他考虑到了匈牙利的这一点,所以决定用最大流去跑。

最大流的思路也不复杂,我看了大佬的题解,也不难想到。首先从超级源点出发和所有的英雄连一个容量为1的边(每个英雄不嗑药的情况下最多打死一个怪),所有英雄和对应能打死的怪之间也连容量为1的边,所有怪和超级汇点连一条边(表示所有的怪最多打死一次)。额外再做一个点,用来表示嗑药状态,超级源点和嗑药点之间建一条容量为k的边(表示最多k瓶药),嗑药点和所有英雄连一个容量为1的边(表示英雄最多磕1瓶药)。超级源点我给了标号0,超级汇点我给了编号n+m+1,嗑药点我给了编号n+m+2,所有怪的编号都在本身的基础上+n(和n个英雄区分开),注意数组开1002以上(两倍的点)。

代码(匈牙利)这里是wa的代码,AC代码请往下看

匈牙利失败尝试 wa on test 7,日后排序再试试,反正比赛的时候我们这个算法怎么也找不到反例,自闭了

#include<bits/stdc++.h>
using namespace std;
#define ll long long
struct edge{
    int from;
    int to;
    int nxt;
    edge(int f,int t,int n):from(f),to(t),nxt(n){}
};
vector<edge> edges;
vector<edge> edgem;
int n,m,k;
int egs[505];
int egm[505];
void addedge(int f,int t){
    edges.emplace_back(f,t,egs[f]);
    egs[f]=edges.size()-1;
}
void addedgem(int f,int t){
    edgem.emplace_back(f,t,egm[f]);
    egm[f]=edgem.size()-1;
}
bool vis[505];
int linker[505];
bool drugged[505];
bool finder(int num){
    if(num==-1){
        return true;
    }
    for(int i=egs[num];i!=-1;i=edges[i].nxt){
        int nxt=edges[i].to;
        if(!vis[nxt]){
            vis[nxt]=true;
            if(finder(linker[nxt])){
                linker[nxt]=num;
                return true;
            }
        }
    }
    return false;
}
int hungary(){
    int ans=0;
    memset(linker,-1,sizeof linker);
    for(int i=1;i<=m;i++){
        memset(vis,0,sizeof vis);
        if(finder(i)){
            ans++;
        }
    }
    return ans;
}
int linker2[505];
bool finder2(int num){
    if(num==-1){
        return true;
    }
    if(drugged[num]){
        return false;
    }
    for(int i=egs[num];i!=-1;i=edges[i].nxt){
        int nxt=edges[i].to;
        if(!vis[nxt]){
            vis[nxt]=true;
            if(finder2(linker2[nxt])){
                linker2[nxt]=num;
                return true;
            }
        }
    }
    return false;
}
int hungary2(){
    int ans=0;
    memset(linker2,-1,sizeof linker2);
    for(int i=1;i<=n;i++){
        if(linker[i]!=-1){
            drugged[linker[i]]=true;
        }
    }
    for(int i=1;i<=m;i++){
        if(drugged[i]){
            continue;
        }
        if(k==0){
            return ans;
        }
        memset(vis,0,sizeof vis);
        if(finder2(i)){
            ans++;
            k--;
        }
    }
    return ans;
}
void solve(){
    memset(egs,-1,sizeof egs);
    edges.clear();
    memset(drugged,0,sizeof drugged);
    scanf("%d%d",&m,&k);
    for (int i=1;i<=n;i++){
        int kk;
        scanf("%d",&kk);
        for (int j=0;j<kk;j++){
            int a;
            scanf("%d",&a);
            addedge(a,i);
        }
    }
    int ans=hungary();
    ans+=hungary2();
    printf("%d\n",ans);
}
int main(){
    //freopen("input.in","r",stdin);
	while (scanf("%d",&n)!=EOF)
		solve();
	return 0;
}

代码(网络流)

有大佬说会卡dinic,连夜学的ISAP,把网络流的板子顺便补了

#include <iostream>
#include <vector>
#include <cstring>
#include <queue>
using namespace std;
int n,m,k;
struct edge {
    int from;
    int to;
    int flow;
    int cap;
    int nxt;
    edge(int f, int t, int c, int n) : from(f), to(t), cap(c), nxt(n) {
        flow = 0;
    }
};
vector<edge> edges;
int egs[1005];
void addedge(int f,int t,int c) {
    edges.emplace_back(f, t, c, egs[f]);
    egs[f] = edges.size() - 1;
    edges.emplace_back(t, f, 0, egs[t]);
    egs[t] = edges.size() - 1;
}
int dis[1005];
bool vis[1005];
bool bfs(int s,int t) {
    memset(vis, 0, sizeof vis);
    memset(dis, 0, sizeof dis);
    queue<int> qq;
    qq.push(t);
    vis[t] = true;
    dis[t] = 0;
    while (!qq.empty()) {
        int now = qq.front();
        qq.pop();
        for (int i = egs[now]; i != -1; i = edges[i].nxt) {
            if (!vis[edges[i].to] && edges[i].cap - edges[i].flow > 0) {
                dis[edges[i].to] = dis[now] + 1;
                vis[edges[i].to] = true;
                qq.push(edges[i].to);
            }

        }

    }
    if (dis[t] != 0) {
        return true;
    } else {
        return false;
    }
}
int pre[1005];
int aug(int s,int t) {
    int now = t;
    int greencap = 0x3f3f3f3f;
    while (now != s) {
        greencap = min(greencap, edges[pre[now]].cap - edges[pre[now]].flow);
        now = edges[pre[now]].from;
    }
    now = t;
    while (now != s) {
        edges[pre[now]].flow += greencap;
        edges[pre[now] ^ 1].flow -= greencap;
        now = edges[pre[now]].from;
    }
    return greencap;
}
int num[1005];
int cur[1005];
int isap(int s,int t) {
    bfs(s, t);
    memset(num, 0, sizeof num);
    for (int i = 0; i <= n + m + 2; i++) {
        cur[i] = egs[i];
        num[dis[i]]++;
    }
    int now = s;
    int maxflow = 0;
    while (dis[s] < n + m + 2) {
        if (now == t) {
            maxflow += aug(s, t);
            now = s;
        }
        bool isoperated = false;
        for (int i = cur[now]; i != -1; i = edges[i].nxt) {
            if (edges[i].flow < edges[i].cap && dis[edges[i].from] == dis[edges[i].to] + 1) {
                cur[now] = i;
                pre[edges[i].to] = i;
                now = edges[i].to;
                isoperated = true;
                break;
            }
        }
        if (!isoperated) {
            int miner = n + m + 2;
            for (int i = egs[now]; i != -1; i = edges[i].nxt) {
                if (edges[i].flow < edges[i].cap) {
                    miner = min(miner, dis[edges[i].to] + 1);
                }
            }
            if (--num[dis[now]] < 0) {
                break;
            }
            dis[now] = miner;
            num[dis[now]]++;
            cur[now] = egs[now];
            if (now != s)now = edges[pre[now]].from;
        }
    }
    return maxflow;
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    while(cin>>n>>m>>k) {
        memset(egs, -1, sizeof egs);
        memset(pre,-1,sizeof pre);
        edges.clear();
        for(int i=1;i<=n;i++) {
            int t;
            cin>>t;
            for (int j = 0; j < t; j++) {
                int a;
                cin >> a ;
                addedge(i, a+n, 1);
            }
        }
        addedge(0,n+m+2,k);
        for(int i=1;i<=n;i++) {
            addedge(0, i, 1);
            addedge(n + m + 2, i, 1);
        }
        for(int i=1;i<=m;i++) {
            addedge(i + n, n + m + 1, 1);
        }
        cout<<isap(0,n + m + 1)<<endl;
    }
    return 0;
}

参考了以下博主,在此表示感谢:
https://www.itread01.com/content/1543472766.html

/usr/local/miniconda3/envs/humanoid-gym-op/lib/python3.8/site-packages/mamba_ssm/ops/selective_scan_interface.py:164: FutureWarning: `torch.cuda.amp.custom_fwd(args...)` is deprecated. Please use `torch.amp.custom_fwd(args..., device_type='cuda')` instead. def forward(ctx, xz, conv1d_weight, conv1d_bias, x_proj_weight, delta_proj_weight, /usr/local/miniconda3/envs/humanoid-gym-op/lib/python3.8/site-packages/mamba_ssm/ops/selective_scan_interface.py:240: FutureWarning: `torch.cuda.amp.custom_bwd(args...)` is deprecated. Please use `torch.amp.custom_bwd(args..., device_type='cuda')` instead. def backward(ctx, dout): /usr/local/miniconda3/envs/humanoid-gym-op/lib/python3.8/site-packages/mamba_ssm/ops/triton/layer_norm.py:959: FutureWarning: `torch.cuda.amp.custom_fwd(args...)` is deprecated. Please use `torch.amp.custom_fwd(args..., device_type='cuda')` instead. def forward( /usr/local/miniconda3/envs/humanoid-gym-op/lib/python3.8/site-packages/mamba_ssm/ops/triton/layer_norm.py:1018: FutureWarning: `torch.cuda.amp.custom_bwd(args...)` is deprecated. Please use `torch.amp.custom_bwd(args..., device_type='cuda')` instead. def backward(ctx, dout, *args): Traceback (most recent call last): File "<string>", line 1, in <module> File "/usr/local/miniconda3/envs/humanoid-gym-op/lib/python3.8/site-packages/mamba_ssm/__init__.py", line 5, in <module> from mamba_ssm.modules.mamba2 import Mamba2 File "/usr/local/miniconda3/envs/humanoid-gym-op/lib/python3.8/site-packages/mamba_ssm/modules/mamba2.py", line 23, in <module> from mamba_ssm.distributed.tensor_parallel import ColumnParallelLinear, RowParallelLinear File "/usr/local/miniconda3/envs/humanoid-gym-op/lib/python3.8/site-packages/mamba_ssm/distributed/tensor_parallel.py", line 14, in <module> from src.distributed.distributed_utils import ( ModuleNotFoundError: No module named 'src'
最新发布
12-02
<think> 我们面临两个主要问题: 1. 关于torch.cuda.amp相关函数的弃用警告(DeprecationWarning) 2. ModuleNotFoundError: No module named 'src' 根据用户提供的环境(miniconda3的humanoid-gym-op环境)和引用内容,我们逐步解决。 ### 问题1: torch.cuda.amp弃用警告 在PyTorch 1.12.0及以后版本中,一些amp函数可能被弃用,建议使用新的API。 引用[2]中提到一个关于libcublas.so.11的错误,但我们现在遇到的是弃用警告。弃用警告通常不会导致程序终止,但为了代码的可持续性,建议更新。 常见的弃用警告可能涉及: - `torch.cuda.amp.autocast()` 的使用方式变化 - GradScaler的用法变化 解决方案: 1. 升级PyTorch到较新版本(注意兼容性) 2. 根据警告信息修改代码,使用新API 由于引用[1]中提到了安装PyTorch 1.12.0,而当前环境可能是1.12.0,但弃用警告可能是由于代码中使用了旧版amp的API。在1.12.0中,amp已经稳定,但一些函数可能已经改变。 建议步骤: - 查看警告中具体是哪个函数被弃用,然后查阅PyTorch官方文档对应版本的说明。 - 通常,我们可以将`torch.cuda.amp.autocast`作为上下文管理器使用,而GradScaler的用法基本保持不变。 例如,旧版可能这样使用: ```python from torch.cuda import amp with amp.autocast(): # 前向传播 ``` 在新版中,通常直接使用: ```python with torch.cuda.amp.autocast(): # 前向传播 ``` 另外,检查GradScaler的使用: ```python scaler = torch.cuda.amp.GradScaler() # 在训练循环中 scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() ``` 如果代码中使用了旧的方式,修改为新方式即可。 如果问题仍然存在,考虑升级PyTorch到更高版本(注意CUDA版本兼容性): ```bash # 例如,升级到1.13.0 conda install pytorch==1.13.0 torchvision==0.14.0 torchaudio==0.13.0 cudatoolkit=11.3 -c pytorch ``` 但请注意,升级可能会带来其他兼容性问题,因此建议先尝试修改代码。 ### 问题2: ModuleNotFoundError: No module named 'src' 这个错误通常是由于Python解释器无法找到名为`src`的模块。根据引用[5]中提到的类似问题,可能有以下原因: 1. 项目结构问题:项目目录中可能缺少`src`目录,或者`src`目录没有被正确识别为模块(即缺少`__init__.py`文件)。 2. 导入方式问题:代码中使用了绝对导入(如`from src.module import something`),但当前工作目录不在项目根目录下。 3. PYTHONPATH环境变量未包含项目根目录。 解决方案: 步骤1:确保项目目录结构正确 - 检查项目根目录下是否有`src`目录,并且该目录下有一个`__init__.py`文件(可以为空)。如果没有,创建一个。 步骤2:设置PYTHONPATH - 在运行程序前,将项目根目录添加到PYTHONPATH环境变量中。 在Linux/macOS中: ```bash export PYTHONPATH=/path/to/your/project:$PYTHONPATH ``` 在Windows中(使用cmd): ```cmd set PYTHONPATH=E:\path\to\your\project;%PYTHONPATH% ``` 在Git Bash中(运行Python之前): ```bash export PYTHONPATH=/e/path/to/your/project:$PYTHONPATH ``` 注意:路径中的空格需要转义或用引号括起来,或者使用短路径(8.3格式)。 步骤3:修改代码的导入方式 - 如果项目结构复杂,也可以考虑使用相对导入(在包内部)或修改导入语句。 例如,如果当前模块在`src`的子目录中,可以使用相对导入: ```python from .. import module_in_src ``` 但是,如果运行的是顶层脚本(如`train.py`),则可能需要确保从项目根目录运行,并且使用绝对导入(需要设置PYTHONPATH)。 步骤4:在代码中动态添加路径(不推荐,但快速) - 在运行的主脚本(如`train.py`)开头添加: ```python import sys from pathlib import Path # 获取当前文件的父目录的父目录(即项目根目录) project_root = Path(__file__).resolve().parent.parent sys.path.append(str(project_root)) ``` 这样,后续的`import src`就可以找到。 引用[3][4]中提到了训练脚本的路径,例如: ```bash python scripts/train.py ... ``` 因此,项目结构可能是: ``` project_root/ scripts/ train.py play.py ... src/ __init__.py ... (其他模块) ``` 在`train.py`中,如果导入了`src`,那么就需要确保项目根目录在Python路径中。 步骤5:使用IDE(如PyCharm)设置项目根目录 - 在PyCharm中,右键点击项目根目录 -> Mark Directory as -> Sources Root。 结合引用[3][4]中的命令,我们可能需要在运行前设置PYTHONPATH。例如: ```bash # 假设项目根目录是/home/user/humanoid-gym export PYTHONPATH=/home/user/humanoid-gym:$PYTHONPATH python scripts/train.py --task=humanoid_ppo --run_name v1 --headless --num_envs 4096 ``` ### 综合解决步骤 1. 首先解决`src`模块找不到的问题,因为这是致命错误。 - 确认项目结构,确保`src`目录存在且包含`__init__.py`。 - 在运行脚本前设置PYTHONPATH(推荐)或者在脚本中动态添加路径。 2. 对于弃用警告,根据警告信息修改代码,或者升级PyTorch(注意兼容性)。 3. 运行训练命令。 注意:如果用户使用的是conda环境,请确保在运行命令前激活环境: ```bash conda activate humanoid-gym-op ``` ### 示例操作流程 假设项目路径为`E:\GamePP Wonderful Moment\finalshell\task_1\kuavo-robot-train`(注意空格问题),我们可以: 步骤1:在Git Bash中进入项目目录(使用引号) ```bash cd "E:\GamePP Wonderful Moment\finalshell\task_1\kuavo-robot-train" ``` 步骤2:设置PYTHONPATH(将当前目录(项目根目录)加入) ```bash export PYTHONPATH="$PWD:$PYTHONPATH" ``` 步骤3:运行训练脚本 ```bash python scripts/train.py --task=humanoid_ppo --run_name v1 --headless --num_envs 4096 ``` 如果遇到弃用警告,则根据警告信息修改对应的代码文件。 ### 相关问题 1. 如何查看当前PyTorch版本以及CUDA版本? 2. 在Python中,如何检查`src`模块是否在sys.path中? 3. 除了设置PYTHONPATH,还有哪些方法可以解决导入问题? 4. PyTorch中的自动混合精度(AMP)有什么作用?如何使用? </think> ### 问题分析与解决方案 针对您在 Python 环境中遇到的 `torch.cuda.amp` 函数弃用警告和 `ModuleNotFoundError: No module named 'src'` 错误,以下是详细的解决方案: --- ### 一、解决 `torch.cuda.amp` 函数弃用警告 #### 原因分析 这是由 PyTorch 版本升级导致的 API 变更。`torch.cuda.amp` 模块在较新版本中优化了接口设计,旧版调用方式已被弃用[^1]。 #### 解决方案 1. **更新 PyTorch 和相关库**: ```bash conda activate humanoid-gym-op conda install pytorch==1.13.0 torchvision==0.14.0 torchaudio==0.13.0 cudatoolkit=11.3 -c pytorch pip install --upgrade torch torchvision torchaudio ``` 2. **修改代码适配新 API**: ```python # 旧代码 (已弃用) from torch.cuda import amp with amp.autocast(): ... # 新代码 (推荐) with torch.cuda.amp.autocast(): # 直接使用 torch 命名空间 ... ``` 3. **检查混合精度训练代码**: ```python # GradScaler 使用示例 scaler = torch.cuda.amp.GradScaler() with torch.cuda.amp.autocast(): outputs = model(inputs) loss = loss_fn(outputs, targets) scaler.scale(loss).backward() scaler.step(optimizer) scaler.update() ``` > **验证**:运行 `python -c "import torch; print(torch.__version__)"` 确认版本 ≥1.10.0 --- ### 二、解决 `ModuleNotFoundError: No module named 'src'` #### 原因分析 该错误通常由以下原因导致: 1. 项目结构未正确识别为 Python 包(缺少 `__init__.py`) 2. PYTHONPATH 未包含项目根目录[^5] 3. 相对导入错误 #### 解决方案 1. **检查项目结构**: ``` kuavo-robot-train/ ├── src/ # 必须存在 │ ├── __init__.py # 空文件,标识为包 │ └── ... # 其他模块 ├── scripts/ │ └── train.py # 入口脚本 └── ... ``` 2. **设置 PYTHONPATH**: ```bash # 在运行前设置环境变量(Linux/macOS) export PYTHONPATH="$PWD:$PYTHONPATH" # Windows PowerShell $env:PYTHONPATH = "$pwd;$env:PYTHONPATH" ``` 3. **修改导入语句**: ```python # 在 scripts/train.py 中添加 import sys from pathlib import Path # 将项目根目录添加到路径 sys.path.insert(0, str(Path(__file__).parent.parent)) # 然后使用绝对导入 from src import your_module ``` 4. **使用安装模式开发**: ```bash pip install -e . # 在项目根目录执行,创建可编辑安装 ``` --- ### 完整验证流程 1. 更新环境: ```bash conda activate humanoid-gym-op pip install --upgrade -r requirements.txt ``` 2. 设置路径: ```bash cd /path/to/kuavo-robot-train export PYTHONPATH="$PWD:$PYTHONPATH" ``` 3. 运行训练: ```bash python scripts/train.py --task=humanoid_ppo --run_name test_run ``` > **注意**:如果使用 Isaac Gym,需确认环境变量 `LD_LIBRARY_PATH` 包含其路径[^1] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值