cf 236 div2 E Strictly Positive Matrix 矩阵阶乘和图上路径(计数)(可达)(最优值)问题

博客讨论了如何将矩阵问题转化为图论问题,特别是如何利用Floyd算法判断图中是否所有点相互可达,从而解决cf 236 div2 E题目的条件。文章提到了矩阵A的幂次B表示路径计数,并解释了在存在自环的情况下,只需检查图的可达性来确定答案。同时,它还引用了其他图相关问题的转换例子。

官方题解:

402E - Strictly Positive Matrix / 403C - Strictly Positive Matrix

Let's look at the matrix a as a connectivity matrix of some graph with n vertices. Moreover, if aij > 0, then we have directed edge in the graph between nodes (i, j). Otherwise, if aij = 0 that graph does not contains directed edge between pair of nodes (i, j). Let b = ak. What does bij means? bij is the number of paths of length exactly k in our graph from vertex i to vertex j. Let pos is an integer, such thata[pos][pos] > 0. That is, we have a loop in the graph. So, if from the vertex pos achievable all other vertexes and vice versa, from all other vertices reachable vertex pos, then the answer is YES, otherwise the answer is NO. If reachability is missing, it is clear that for anyk akipos = 0. If reachability there, we will be able to reach self-loop, use self-loop "to twist", and after that we will go to some another vertex.

大概题意:给定一个矩阵A(n*n的),对角线为1,其它位置为0或1.B= A^k,问是否存在某个k使得B中每个元素都为1.

矩阵阶乘和图上路径计数问题的转换:

(矩阵的元素为A[i][j] = 1代表图上点i可达点j,特殊的A[i][i] = 1。表示点i存在自环。

转化为图的问题。对应的图为:

n个点,A[i][j] = 1,则i和j之间连边,否者不连。

则B = A^k,B[i][j]代表的含义为,从i到j的路径长度为k的路径的个数。


由于本题中对角线为1,即任意点存在子环,则如果存在从i到j的长度为k 的路径,则存在从i到j长度为k+1,k+2.。。的路径。

所以只需判断可到达即可,即任一点可到达其他所有点。可用floyd,判强连通为1,或判任意点都和同一点在一个环上即可(必要条件)。

本题是判断是否存在,则用必要条件去判断即可

floyd的解法和判任意点都和同一点在一个环上的解法

int n;
bitset<2010>f[2010];
int main ()
{
    RI(n);
    REP(i, n) REP(j, n)
    {
        int x;
        RI(x);
        f[i][j] = !!x;
    }
    REP(k, n) REP(i, n)
    if (f[i][k]) f[i] |= f[k];
    int fla = 1;
    REP(i, n) REP(j, n) if (!f[i][j])
    {
        fla = 0; break;
    }
    if (fla) puts("YES");
    else puts("NO");
    return 0;
}
int n;
bool f[2010][2010];
bool used[2010], rused[2010];
void dfs(int u)
{
    used[u] = 1;
    REP(i, n) if (f[u][i] && !used[i]) dfs(i);
}
void rdfs(int u)
{
    rused[u] = 1;
    REP(i, n) if (f[i][u] && !rused[i]) rdfs(i);
}
int main ()
{
    RI(n);
    REP(i, n) REP(j, n)
    {
        int x;
        RI(x);
        f[i][j] = !!x;
    }

    dfs(0);
    rdfs(0);
    int fla = 1;
    REP(i, n) if (!used[i] || !rused[i])///都为1说明成环
        fla = 0; break;

    if (fla) puts("YES");
    else puts("NO");
    return 0;
}


下题是图上路径计数问题转化成矩阵阶乘问题:

ac自动机中求长度为L的特定字符串的个数, AC自动机 其实 就是创建了一个状态的转移图(也是一个图),思想很重要

详见:http://www.cnblogs.com/kuangbin/p/3164106.html

中的

POJ 2778 DNA Sequence

HDU 2243 考研路茫茫——单词情结


另:fzu一题,Problem 2173 Nostop

竟然可以求最优值,涨了姿势。(从点1到点n的经过k条边,的最短路径值问题)

正确性,还待理解(只要满足结合律???)

ps:本题中不允许在一点停留,所以初始化对角线为INF。这样就没办法建立单位1矩阵,所以在快速幂中,第一个是赋值,之后才是乘法

//#pragma warning (disable: 4786)
//#pragma comment (linker, "/STACK:16777216")
//HEAD
#include <cstdio>
#include <ctime>
#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 FE(i, a, b) for(int i = (a); i <= (b); ++i)
#define FD(i, b, a) for(int i = (b); i>= (a); --i)
#define REP(i, N) for(int i = 0; i < (N); ++i)
#define CLR(A,value) memset(A,value,sizeof(A))
#define CPY(a, b) memcpy(a, b, sizeof(a))
#define FC(it, c) for(__typeof((c).begin()) it = (c).begin(); it != (c).end(); it++)
//INPUT
#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)
#define RS(s) scanf("%s", s)
//OUTPUT
#define WI(n) printf("%d\n", n)
#define WS(s) printf("%s\n", s)

typedef long long LL;
const LL INF = 1LL * 1e18;
const double eps = 1e-10;
const int maxn = 100010;
const int MOD = 1000000007;

struct Metrix{
    LL tab[55][55];
    int n;
    Metrix(int n)
    {
        this->n = n;
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                tab[i][j] = INF;
    }
    Metrix operator*(Metrix a)
    {
        Metrix ret(n);
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                for (int r = 1; r <= n; r++)
                    ret.tab[i][j] = min(ret.tab[i][j], tab[i][r] + a.tab[r][j]);
        return ret;
    }
};
int n, T, m, k;
Metrix quick_pow(Metrix a, int k)
{
    Metrix ret(n);
    int st = 0;
    while (k)
    {
        if (k & 1)
        {
            if (st) ret = ret * a;
            else ret = a;
            st = 1;
        }
        k >>= 1;
        a = a * a;
    }
    return ret;
}
int main ()
{
    RI(T);
    while (T--)
    {
        RIII(n, m, k);
        Metrix tmp(n);
        for (int i = 0; i < m; i++)
        {
            int x, y;
            LL z;
            cin >> x >> y >> z;
            tmp.tab[x][y] = min(tmp.tab[x][y], z);
        }
        Metrix ans = quick_pow(tmp, k);
        if (ans.tab[1][n] == INF) ans.tab[1][n] = -1;
        cout << ans.tab[1][n] << endl;
    }
    return 0;
}
/***
1
3 2 2
1 2 2
2 3 3

1
5 5 3
1 2 1
2 5 1
1 3 10
3 4 10
4 5 10
*/




<think>嗯,用户遇到了指数平滑预测时的错误,提示“endog must be strictly positive when using multiplicative trend or seasonal components”。首先,我需要回忆一下指数平滑模型的类型要求。 记得指数平滑模型有不同的组合,比如加法趋势、乘法季节等。当使用乘法成分(乘法趋势或乘法季节性)时,要求数据必须严格大于零,因为乘法模型涉及到相乘的成分,如果数据中有零或负数,会导致计算错误,比如除以零或者得到负数结果,这时候模型就无法正常运行了。所以用户的输入数据可能包含非正数,导致了这个错误。 接下来,应该如何处理这个问题呢?可能的解决方法有几个方向。首先是检查数据中的零或负,看看这些是否合理,是否可以被处理。比如,如果是销售数据,零可能有意义,但如果是温度数据,负数也可能存在。这时候需要根据具体情况来处理。 如果是数据中存在非正数,但用户仍然希望使用乘法模型,可以考虑将数据进行平移,比如加一个常数,使得所有数据点都变成正数。例如,加上数据最小绝对再加上一个小的epsilon,这样可以确保数据严格为正。但需要注意,这种处理可能会影响模型的预测结果,需要后续调整。 另一个方法是改用加法模型。如果用户的数据允许,将trendseasonal参数设置为'add'而不是'mul',这样就不会要求数据必须为正了。但这样可能会影响模型对趋势季节性的捕捉,尤其是当季节波动的幅度随数据水平变化时,加法模型可能不如乘法模型准确。 另外,检查数据是否有缺失或者异常,这些也可能导致问题。比如,某些缺失被错误地填充为零,这时候需要正确处理缺失,比如用插方法填补,而不是保留为零。 还有可能需要检查使用的库是否正确,比如statsmodels中的ETSModel是否正确配置了趋势季节性参数,是否有误用了乘法成分。有时候参数设置错误也可能导致不必要的约束被触发。 总结来说,解决方案包括数据预处理(平移或转换)、模型调整(改用加法成分)、数据检查参数验证。需要根据具体情况选择合适的方法,并在处理数据后重新运行模型,确保错误不再出现。同时,用户需要注意数据转换可能带来的影响,比如预测结果需要逆向转换,或者在解释结果时考虑平移的影响。</think>### 问题分析 指数平滑模型(ETS)报错 `endog must be strictly positive` 是由于在使用**乘法趋势(multiplicative trend)**或**乘法季节性(multiplicative seasonal)**成分时,输入数据中存在非正数(零或负数)。乘法模型依赖比计算,因此要求所有观测 $y_t > 0$[^1]。 --- ### 解决方法 #### 1. **数据预处理:确保严格正** - **适用场景**:数据中存在零或负数,但业务允许调整数据范围。 - **操作步骤**: 1. 对数据整体平移,确保最小严格大于零: $$ y_{\text{new}} = y + \epsilon - \min(y) $$ 其中 $\epsilon$ 是微小正数(如 $0.001$)。 2. 对非负数据中的零替换为极小: ```python data[data <= 0] = 1e-6 ``` #### 2. **改用加法模型** - **适用场景**:数据允许忽略乘法效应(如趋势/季节性波动幅度不随数据量级变化)。 - **操作步骤**: 在模型参数中强制指定趋势季节性为加法形式: ```python from statsmodels.tsa.exponential_smoothing.ets import ETSModel model = ETSModel(data, trend='add', seasonal='add', seasonal_periods=12) ``` #### 3. **数据转换** - **适用场景**:数据分布存在明显偏态(如指数增长)。 - **操作步骤**: 1. 对数据取对数转换,将乘法关系转化为加法: $$ \log(y) = \text{Trend} + \text{Seasonal} + \text{Error} $$ 2. 预测后需反向转换: ```python model = ETSModel(np.log(data), trend='mul', seasonal='mul') forecast = np.exp(model.fit().forecast(steps=10)) ``` --- ### 代码示例 ```python import numpy as np from statsmodels.tsa.exponential_smoothing.ets import ETSModel # 原始数据(含非正) data = np.array([10, 5, 3, 0, -2, 8, 12]) # 方法1:数据平移 epsilon = 1e-6 shifted_data = data + abs(data.min()) + epsilon # 方法2:改用加法模型 model_add = ETSModel(data, trend='add', seasonal='add', seasonal_periods=4) # 方法3:对数转换(仅适用于严格正数) positive_data = data.copy() positive_data[positive_data <= 0] = 1e-6 model_log = ETSModel(np.log(positive_data), trend='mul', seasonal='mul') ``` --- ### 关键注意事项 1. **数据平移的影响**:平移会改变数据分布,需评估对预测结果的可解释性影响。 2. **模型选择依据**:乘法模型更适用于波动幅度随数据量级变化的场景(如销售额的季节性放大效应)[^2]。 3. **参数验证**:检查 `trend` `seasonal` 参数是否误设为 `'mul'`。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值