poj2135(84/600)

FJ在农场展示路径,他的农场有N个字段,用M条路径连接。他想找到一条从房子出发,经过一些字段,最后到达谷仓的最短路线,且返回时不能重复走同一路径。计算出这样的最短路线长度。

When FJ’s friends visit him on the farm, he likes to show them around. His farm comprises N (1 <= N <= 1000) fields numbered 1..N, the first of which contains his house and the Nth of which contains the big barn. A total M (1 <= M <= 10000) paths that connect the fields in various ways. Each path connects two different fields and has a nonzero length smaller than 35,000.

To show off his farm in the best way, he walks a tour that starts at his house, potentially travels through some fields, and ends at the barn. Later, he returns (potentially through some fields) back to his house again.

He wants his tour to be as short as possible, however he doesn’t want to walk on any given path more than once. Calculate the shortest tour possible. FJ is sure that some tour exists for any given farm.
Input
* Line 1: Two space-separated integers: N and M.

  • Lines 2..M+1: Three space-separated integers that define a path: The starting field, the end field, and the path’s length.
    Output
    A single line containing the length of the shortest tour.
    Sample Input
    4 5
    1 2 1
    2 3 1
    3 4 1
    1 3 2
    2 4 2
    Sample Output
    6

这玩意太简单了不说了…

//#include<bits/stdc++.h>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<queue>
using namespace std;
int INF=0x3f3f3f3f;
const int Vmax=2005; //需要拆点的话记得加倍
namespace MCMF{
    struct Edge{
        int from,to,cap,flow,cost;
        Edge(int u,int v,int c,int f,int w):from(u),to(v),cap(c),flow(f),cost(w){}
    };

    int n,m;
    vector<Edge>edges;
    vector<int>G[Vmax];
    int inq[Vmax];  //是否在队列中
    int d[Vmax];    //Bellman-Ford
    int p[Vmax];    //上一条弧
    int a[Vmax];    //可改进量

    void init(int _Vsz){
        n=_Vsz;
        for(int i=0;i<=n;i++) G[i].clear();
        edges.clear();
    }

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

    bool SPFA(int s,int t,int& flow,long long& cost){
        for(int i=0;i<=n;i++) d[i]=INF;
        memset(inq, 0, sizeof(inq));
        d[s]=0;
        inq[s]=1;
        p[s]=0;
        a[s]=INF;

        queue<int>q;
        q.push(s);
        while(!q.empty()){
            int u=q.front();
            q.pop();
            inq[u]=0;
            for(int i=0;i<G[u].size();i++){
                Edge& e=edges[G[u][i]];
                if(e.cap>e.flow&&d[e.to]>d[u]+e.cost){
                    d[e.to]=d[u]+e.cost; //松弛操作
                    p[e.to]=G[u][i];    //记录上一条边信息
                    a[e.to]=min(a[u], e.cap-e.flow);
                    if(!inq[e.to]){
                        q.push(e.to);
                        inq[e.to]=1;
                    }
                }
            }
        }
        if(d[t]==INF) return false; //s-t 不联通,失败退出
        flow+=a[t];
        cost+=(long long)d[t]*(long long)a[t];
        for(int u=t;u!=s;u=edges[p[u]].from){
            edges[p[u]].flow+=a[t];
            edges[p[u]^1].flow-=a[t];
        }
        return true;
    }

    int MincostMaxflow(int s,int t,long long& cost){
        int flow=0;
        cost=0;
        while(SPFA(s, t, flow, cost));
        return flow;
    }
}
int main()
{
    int n,m,q,w,e;
    cin>>n>>m;
    MCMF::init(n+10);
    MCMF::adde(0,1,2,0);
    for(int a=1;a<=m;a++)
    {
        scanf("%d%d%d",&q,&w,&e);
        MCMF::adde(q,w,1,e);
        MCMF::adde(w,q,1,e);
    }
    int st=0,ed=n+1;
    MCMF::adde(n,n+1,100,0);
    long long minCost, maxFlow;
    maxFlow = MCMF::MincostMaxflow(st, ed, minCost);
    cout<<minCost<<endl;
}
<think>首先,用户想了解POJ 3104题目的详细信息,包括题目描述、解题思路和代码实现。用户提供了几个引用,我需要参考这些引用,但要根据用户的问题来整合。 回顾用户提供的引用: - 引用[1]:是关于POJ 3104 "Drying"的二分查找解法。它解释了算法:对于每个衣服的水量ai,如果ai小于等于mid(时间),则自然晾干;否则,需要机器烘干和自然晾干结合,并给出了公式x1 >= (ai - mid)/(k-1),其中k是烘干机的效率。代码是用C++写的,实现了二分查找。 - 引用[2]:简要描述了输入格式:第一行是n(衣服数量),第二行是ai(每个衣服的初始水量),第三行是k(烘干机的效率)。 - 引用[3]:提供了数学计算+二分的题解,解释了公式:吹风次数k = (a[i] - mid)/(m-1),其中m是k(烘干效率),但这里变量名冲突了。应该是k是烘干效率,吹风次数是ceil((a[i]-mid)/(k-1))。 - 引用[4]:类似引用[2],描述了输入格式。 用户的问题是:"我想查找POJ 3104题目的相关信息,可能包括题目描述、解题思路、代码实现等 请问POJ 3104题目解析及代码实现"。 所以,我需要提供: 1. 题目描述:基于引用,POJ 3104是"Drying"问题。输入包括n个衣服的初始水量ai和烘干机效率k。目标是找到最小时间使所有衣服干燥。衣服每分钟自然晾干1单位水;使用烘干机每分钟晾干k单位水,但烘干机每分钟只能用于一件衣服。 2. 解题思路:使用二分查找来最小化时间。思路是假设一个时间mid,检查是否能在mid时间内干燥所有衣服。对于每件衣服,如果ai <= mid,自然晾干即可;否则,需要烘干机帮助,时间为ceil((ai - mid)/(k-1))总烘干时间不能超过mid。 3. 代码实现:基于引用[1]的C++代码,我可以提供一个清晰的版本。 系统指令要求: - 行内数学表达式用$...$,例如 $x^2$。 - 独立公式用$$...$$并单独成段。 - 使用中文回答。 - 生成相关问题。 - 回答中引用的段落末尾自然地添加引用标识[^1]。 - 回答结构清晰,逐步解决问题,保证真实可靠。 组织回答: 1. **题目描述**:描述POJ 3104问题。 2. **解题思路**:详细解释二分查找方法,数学公式。 3. **代码实现**:提供C++代码(基于引用[1]),并解释关键部分。 4. **相关问题**:在末尾生成相关问题。 确保LaTeX语法正确: - 例如,公式 $(ai - mid)/(k-1)$ 应该用LaTeX表示:$\frac{a_i - \text{mid}}{k-1}$。 - 向上取整用 $\lceil \cdot \rceil$。 代码块要正确格式。 现在,构建回答。 **题目描述**: POJ 3104 "Drying" 是一个关于烘干衣服的问题。给定n件衣服,每件衣服有一个初始水量 $a_i$($1 \leq a_i \leq 10^9$)。衣服每分钟自然晾干1单位水。如果使用烘干机,每分钟可以额外晾干k单位水($1 \leq k \leq 10^9$),但烘干机每分钟只能用于一件衣服。目标是找到最小时间使所有衣服干燥[^2][^4]。 **解题思路**: 使用二分查找来优化时间。设最小时间为T。对于每个候选时间mid,检查是否能在mid分钟内干燥所有衣服。 - 对于一件衣服,如果初始水量 $a_i \leq \text{mid}$,则自然晾干即可。 - 如果 $a_i > \text{mid}$,则需要使用烘干机。设自然晾干时间为 $x_2$,烘干时间为 $x_1$,则总时间 $x_1 + x_2 = \text{mid}$,且晾干的水量为 $k \cdot x_1 + x_2 \geq a_i$。 代入 $x_2 = \text{mid} - x_1$,得: $$ k \cdot x_1 + (\text{mid} - x_1) \geq a_i $$ 简化得: $$ (k-1) x_1 \geq a_i - \text{mid} $$ 因此,烘干时间 $x_1 \geq \frac{a_i - \text{mid}}{k-1}$。由于 $x_1$ 必须是整数且不能为负,实际所需烘干时间为 $\lceil \frac{a_i - \text{mid}}{k-1} \rceil$。 检查时,计算所有衣服的烘干时间之和 $\sum \lceil \frac{a_i - \text{mid}}{k-1} \rceil$。如果这个和小于等于mid,则mid可行[^3]。 注意:当 $k=1$ 时,烘干机无效,只能自然晾干,所以最小时间是 $\max(a_i)$。 **代码实现**: 以下是基于C++的实现: ```cpp #include <iostream> #include <algorithm> #include <cmath> using namespace std; const int MAXN = 100010; int a[MAXN]; int n, k; bool check(int mid) { long long need = 0; // 总烘干时间 for (int i = 0; i < n; i++) { if (a[i] <= mid) continue; // 计算所需烘干时间,向上取整 need += (long long)ceil((double)(a[i] - mid) / (k - 1)); if (need > mid) return false; // 超过时间限制 } return true; } int main() { cin >> n; for (int i = 0; i < n; i++) { cin >> a[i]; } cin >> k; sort(a, a + n); // 排序有助于优化,但非必需 if (k == 1) { cout << a[n-1] << endl; // 最大水量 return 0; } int l = 0, r = a[n-1]; // 时间范围,最大可能时间为最大水量 while (l < r) { int mid = l + (r - l) / 2; // 避免溢出 if (check(mid)) { r = mid; // 可行,尝试更小时间 } else { l = mid + 1; // 不可行,增加时间 } } cout << l << endl; return 0; } ``` 代码解释: - `check(mid)` 函数检查mid时间是否足够。 - 使用`long long`防止溢出,因为水量可能很大。 - 当$k=1$时,直接输出最大水量。 - 二分查找范围是[0, max(a_i)]。 **相关问题**: 在末尾生成几个相关问题。 确保引用: - 在描述中添加[^2][^4],但用户提供的引用是参考,所以我可以自然地引用它们。 最终回答结构: - 题目描述 - 解题思路 - 代码实现 - 相关问题 </think> ### POJ 3104 "Drying" 题目解析及代码实现 #### 题目描述 POJ 3104 "Drying" 是一个优化问题:给定 $n$ 件衣服,每件有初始水量 $a_i$($1 \leq a_i \leq 10^9$)。衣服每分钟自然晾干 1 单位水;若使用烘干机,每分钟可额外干燥 $k$ 单位水($1 \leq k \leq 10^9$),但每分钟只能处理一件衣服。目标是找到最小时间 $T$,使得所有衣服完全干燥[^2]。 **输入格式**: - 第一行:整数 $n$(衣服数量) - 第二行:$n$ 个整数 $a_i$(初始水量) - 第三行:整数 $k$(烘干机效率) **输出格式**: 最小干燥时间 $T$。 --- #### 解题思路 使用**二分查找**求解最小时间 $T$。核心思想是:假设一个候选时间 $\text{mid}$,检查是否能在 $\text{mid}$ 分钟内干燥所有衣服。验证函数基于以下逻辑: 1. **自然晾干**:若 $a_i \leq \text{mid}$,衣服自然晾干即可,无需额外处理。 2. **机器辅助**:若 $a_i > \text{mid}$,需结合烘干机和自然晾干。设: - $x_1$:烘干机使用时间(每分钟干燥 $k$ 单位) - $x_2$:自然晾干时间(每分钟干燥 1 单位) 总时间约束为 $x_1 + x_2 = \text{mid}$,水量约束为 $k \cdot x_1 + x_2 \geq a_i$。 代入 $x_2 = \text{mid} - x_1$ 得: $$ k \cdot x_1 + (\text{mid} - x_1) \geq a_i \implies (k-1) x_1 \geq a_i - \text{mid} $$ 因此,烘干时间需满足: $$ x_1 \geq \frac{a_i - \text{mid}}{k-1} $$ 实际计算时,需对 $\frac{a_i - \text{mid}}{k-1}$ **向上取整**,即 $\lceil \frac{a_i - \text{mid}}{k-1} \rceil$。 3. **可行性检查**:所有衣服的烘干时间之和 $\sum \lceil \frac{a_i - \text{mid}}{k-1} \rceil$ 必须 $\leq \text{mid}$。 4. **特例**:若 $k=1$,烘干机无效,最小时间 $T = \max(a_i)$。 **算法步骤**: 1. 对 $a_i$ 排序(可选优化)。 2. 二分查找 $T$:初始范围 $[0, \max(a_i)]$。 - 若 $\text{check}(\text{mid})$ 返回 `true`,则尝试更小时间($r = \text{mid}$)。 - 否则尝试更大时间($l = \text{mid} + 1$)。 --- #### 代码实现(C++) ```cpp #include <iostream> #include <algorithm> #include <cmath> using namespace std; const int MAXN = 100010; int a[MAXN]; int n, k; // 检查mid时间是否可行 bool check(int mid) { long long need = 0; // 总烘干时间(防溢出) for (int i = 0; i < n; i++) { if (a[i] <= mid) continue; // 自然晾干即可 need += (long long)ceil((double)(a[i] - mid) / (k - 1)); // 向上取整 if (need > mid) return false; // 超过时间限制 } return need <= mid; } int main() { cin >> n; for (int i = 0; i < n; i++) cin >> a[i]; cin >> k; if (k == 1) { cout << *max_element(a, a + n) << endl; // 特例:k=1时直接输出最大值 return 0; } sort(a, a + n); // 排序优化二分 int l = 0, r = a[n - 1]; // 时间范围 [0, 最大水量] while (l < r) { int mid = l + (r - l) / 2; // 避免溢出 if (check(mid)) r = mid; // 可行,尝试更小时间 else l = mid + 1; // 不可行,增加时间 } cout << l << endl; return 0; } ``` **代码说明**: - **`check` 函数**:计算每件衣服所需烘干时间,并检查总和是否 $\leq \text{mid}$。 - **向上取整处理**:使用 `ceil((double)(a[i] - mid) / (k - 1))` 确保精度。 - **时间复杂度**:$O(n \log (\max(a_i)))$,高效处理大数据范围。 - **注意事项**:当 $k=1$ 时需单独处理,避免除零错误。 --- #### 相关问题 1. 如何证明二分查找在该问题中的正确性? 2. 当 $k$ 接近 1 时,算法性能是否会退化?如何优化? 3. 是否存在其他方法(如贪心或动态规划)解决此问题? 4. 在实现中,为什么使用 `long long` 存储烘干时间? [^1]: POJ 3104 Drying (二分) 解题思路及代码实现参考。 [^2]: POJ-3104 Drying 输入格式描述。 [^3]: Poj---3104 数学计算+二分操作详解。 : POJ - 3104 Drying 题目约束说明。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值