2014牡丹江 区域赛 Building Fire Stations

本文介绍了一种解决树形结构中设备放置问题的方法,通过二分搜索找到使所有节点到最近设备的距离最小化的方案。文章详细解释了算法流程,并提供了实现代码。

给一棵最多2*10^5个结点的树,选择两个结点放置设备,要求所有结点其到最近设备的最远距离最小,求出这个最小距离。


最大值最小,首先想到二分。二分一个最大距离M,先以1号结点bfs出每个结点的深度。任选一个最大深度的结点,则离他距离M的父结点u上必须要放置一个设备。然后再以u进行bfs,同样的选择出第二个结点。再把选择的两个设备结点加入队列bfs,看是否能够遍历所有点,若能就满足。

zju上面做的,dfs会栈溢出。第一次以一号结点bfs可以预处理,之后直接取出最大深度的点就行。有可能两次找的放置设备的点相同,注意特判一下。二分过程完成后,有可能最后一次判断不成立,此时得到的两个设备的点不是题目所求,需要再判断一次。具体见代码。


//#include <bits/stdc++.h>
#include <cstdio>
#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 REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
//OTHER
#define PB push_back
#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)
typedef long long LL;
typedef unsigned long long ULL;
typedef vector <int> VI;
const int INF = 0x3f3f3f3f;
const double EPS = 1e-9;
const int MOD = 1000000007;
const double PI = acos(-1.0);
const int maxn = 200010;

int n, M, rt1, rt2, mdrt;
VI G[maxn];
int num[maxn], fa[maxn], pre[maxn];
//指定深度任选的一个点,第一次bfs的父亲结点,第二次bfs父亲结点
bool vis[maxn];

void init()
{
    REP(i, n + 1)   G[i].clear();
}

struct Node{
    int id, d;
    Node() {}
    Node(int a, int b) : id(a), d(b) {}
}t;

int bfs(int s, int ff[])
{
    CLR(vis, 0);
    queue<Node> Q;
    Q.push(Node(s, 0));
    vis[s] = 1, ff[s] = 0;
    int md = 0;
    while (!Q.empty())
    {
        t = Q.front(); Q.pop();
        int u = t.id;
        num[t.d] = u;
        md = max(md, t.d);
        REP(i, G[u].size())
        {
            int v = G[u][i];
            if (!vis[v])
            {
                vis[v] = 1;
                ff[v] = u;
                Q.push(Node(v, t.d + 1));
            }
        }
    }
    return md;
}

int fun()    //标记两个设备能到达的点
{
    CLR(vis, 0);
    int cnt = 0;
    queue<Node> Q;
    vis[rt1] = vis[rt2] = 1;
    Q.push(Node(rt1, 0)), Q.push(Node(rt2, 0));
    while (!Q.empty())
    {
        t = Q.front(); Q.pop();
        if (t.d >= M)   continue;
        int u = t.id;
        REP(i, G[u].size())
        {
            int v = G[u][i];
            if (!vis[v])
            {
                vis[v] = 1;
                Q.push(Node(v, t.d + 1));
            }
        }
    }
    FE(i, 1, n)
        if (vis[i])
            cnt++;
    return cnt;
}

bool ok()
{
    rt1 = mdrt;
    REP(i, M)   rt1 = pre[rt1];
    int md = bfs(rt1, fa);
    rt2 = num[md];
    REP(i, M)   rt2 = fa[rt2];
    int cnt = fun();
    if (cnt >= n)
    {
        if (rt1 == rt2)     //特判两个点相等时
        {
            if (rt1 + 1 <= n)   rt2 = rt1 + 1;
            else        rt2 = rt1 - 1;
        }
        return 1;
    }
    return 0;
}

int main()
{
    int T, x, y;
    RI(T);
    while (T--)
    {
        RI(n);
        init();
        REP(i, n - 1)
        {
            RII(x, y);
            G[x].PB(y), G[y].PB(x);
        }
        int md = bfs(1, pre);
        mdrt = num[md];
        int L = 0, R = md;
        while (L <= R)
        {
            M = (L + R) >> 1;
            if (ok())  R = M - 1;
            else    L = M + 1;
        }
        M = L; ok();  //求得最小距离后再判断一次得出放置设备点
        printf("%d %d %d\n", L, rt1, rt2);
    }
    return 0;
}
/*
8
8
1 2
1 3
2 4
2 5
3 6
5 7
5 8
ans: 2 1 2
*/


                
<think> 我们正在处理用户关于SWAT无法打开气象站数据(weather stations)的问题。根据用户提供的引用内容,特别是引用[1]和引用[3],我们可以找到一些相关步骤和可能的解决方案。 引用[1]提到: 打开Write Input Tables - Weather Stations,选择气象数据库。这里有很多备用选项,可以导入其他数据库,也可以自己输入。我们选择CFSR_World(https://www.bilibili.com/video/BV1H7411n7Vs下提供了链接),需要将下载到的CFSR_World.mdb手动复制到项目下的SWAT2012.mdb数据库中,如下图所示:[^1] 引用[3]提到: ①Write Input Tables->Weather Stations 打开Weather Generator Data选项卡->下拉选择WGEN_user ②Rainfall Data(降水pcp) 勾选Raingages->选择Daily->导入索引表 其余四项同理,对应关系如下,全部完成后点击OK 注意:如果出现提示日期语法错误,打开控制面板->时钟和区域->区域->更改日期、时和数字格式->短日期->yyyy/M/d [^3] 根据这些引用,我们可以推测用户可能在打开气象站数据时遇到问题,可能的原因和解决方案如下: 1. **数据库文件缺失或路径错误**:引用[1]中提到需要将下载的CFSR_World.mdb手动复制到项目下的SWAT2012.mdb数据库中。因此,检查是否正确复制了数据库文件,以及是否放在了正确的项目路径下。 2. **日期格式错误**:引用[3]中提到如果出现日期语法错误,需要更改系统的短日期格式为yyyy/M/d。这可能是导致无法打开气象站数据的一个常见原因,因为日期格式不匹配可能导致程序解析错误。 3. **索引表导入问题**:引用[3]中详细描述了导入索引表的过程,包括降雨数据和其他四项数据。确保在Weather Generator Data选项卡中正确选择了WGEN_user,并且为每一项数据(降水、温度、太阳辐射、风速、相对湿度)都正确导入了索引表。 4. **步骤操作遗漏**:引用[3]还提到了在完成天气数据编辑后,需要进入Write Input Tables->Select Tables to Write,点击Select All然后点击Create Tables。如果这一步没有执行,可能导致气象站数据没有被正确写入。 5. **气象数据库选择问题**:引用[1]提到选择气象数据库时有很多备用选项,确保选择的是正确的数据库(如CFSR_World),并且已经正确导入。 因此,针对用户的问题,我们可以建议以下解决办法: **步骤1:检查数据库文件** - 确保已经下载了所需的气象数据库(如CFSR_World.mdb)。 - 将该数据库文件复制到项目目录下的SWAT2012.mdb数据库中(注意:这里可能是需要将CFSR_World.mdb中的表导入到SWAT2012.mdb中,或者替换?具体请参考视频或文档说明)。 **步骤2:更改系统日期格式** - 打开控制面板 -> 时钟和区域 -> 区域 -> 更改日期、时和数字格式。 - 在“短日期”设置中,将其改为“yyyy/M/d”格式,然后点击确定。 **步骤3:正确导入索引表** - 按照引用[3]的步骤: a. 打开Write Input Tables -> Weather Stations。 b. 在Weather Generator Data选项卡中,从下拉菜单中选择WGEN_user。 c. 分别对五项气象数据(Rainfall, Temperature, Solar, Wind, Relative Humidity)进行设置: - 勾选相应的数据类型(如降雨数据勾选Raingages,选择Daily)。 - 导入对应的索引表(确保索引表路径正确且文件无误)。 d. 全部完成后点击OK。 **步骤4:写入输入表** - 完成天气数据编辑后,转到Write Input Tables -> Select Tables to Write。 - 点击Select All(选择所有表),然后点击Create Tables(创建表)。 **步骤5:重新启动软件或项目** - 完成上述步骤后,关闭SWAT相关软件,重新打开项目,尝试打开气象站数据。 如果以上步骤仍然不能解决问题,可能是其他原因,如项目文件损坏、数据库损坏或软件版本兼容性问题。建议检查软件版本和数据库版本是否匹配,并查看错误日志(如果有)以获得更多信息。 §§相关问题§§ 1. SWAT模型中的气象数据库如何准备? 2. 如何解决SWAT模型中的日期格式错误问题? 3. SWAT模型中的索引表是什么?如何创建? </think> 根据您提供的引用内容,SWAT无法打开气象站数据(weather Stations)的常见解决方案如下: ### 解决方案步骤 1. **检查日期格式设置**(引用[3]关键提示) 打开控制面板 → 时钟和区域区域 → 更改日期、时和数字格式 → 短日期 → 设置为 `yyyy/M/d` 格式。这是解决日期语法错误的必要操作[^3]。 2. **确认数据库文件集成**(引用[1]关键步骤) 确保气象数据库文件(如 `CFSR_World.mdb`)已手动复制到项目目录下的 `SWAT2012.mdb` 中。外部数据库需通过物理复制集成到主数据库才能被识别[^1]。 3. **正确配置天气生成器**(引用[2][3]操作流程) - 打开 `Write Input Tables → Weather Stations` - 在 `Weather Generator Data` 选项卡下拉选择 `WGEN_user` - 按顺序导入五项气象数据的索引表: ``` 降水(pcp) → Raingages → Daily → 导入索引表 温度(tmp) → Temperature → Daily → 导入索引表 太阳辐射(slr) → Solar → Daily → 导入索引表 风速(wnd) → Wind → Daily → 导入索引表 相对湿度(hmd) → Relative Humidity → Daily → 导入索引表 ``` - 全部完成后点击 `OK`,最后在 `Select Tables to Write` 中 `Select All` → `Create Tables`[^2][^3]。 4. **验证土地利用分类兼容性**(引用[4]隐含关联) 检查土地覆盖/利用图是否通过 `look up表` 正确映射了4位SWAT代码,不兼容的分类可能导致气象数据读取异常[^4]。 --- ### 关键注意事项 - **路径规范**:避免中文字符和特殊符号的路径名,优先使用全英文路径 - **文件权限**:以管理员身份运行ArcSWAT,确保有数据库写入权限 - **版本匹配**:确认气象数据库(如CFSR_World)与SWAT2012版本兼容
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值