zoukankan      html  css  js  c++  java
  • ACM-图论-同余最短路

    https://www.cnblogs.com/31415926535x/p/11692422.html

    一种没见过的处理模型,,记录一下,,主要是用来处理一个多元一次方程的解的数量的问题,,数据量小时可以用看成背包处理,,数据很大时可以转换成最短路模型+一点数学来处理,,(体积模域下的最短路的问题,,求的一个最简的表示形式有模数来得到所有解

    墨墨的等式

    题目

    因为只是求满足的解的数量,,所以可以将方程转换成一个模方程组,,这样的方程组的解显然也是原来的解的子集,,同时可以利用模数来得到所有解,,

    模数的选择是最小的那个系数,,因为如果任意选择,,会出现一些多考虑的情况

    弄 mi 个点,表示从0到mi-1的所有数,,建边的方法是 i->(i+a[j])%mi 边权为 a[j] ,,表示从i这个点变成后面一个数的费用,,(因为两边都是取模的,,所以每一个数取几次后的和的余数就是那些经过的点,,也就是说一条路径就是得到一个右边为 i(mod mi) 的一个最小解,,这个最小的解就是费用和,,也就是一条最短路dis[i]

    这样我们对于每一个取模的右边的B都计算一下区间里的数量,,,(计算这玩意推错了一次,,emmm

    参考

    #include <bits/stdc++.h>
    #define aaa cout<<233<<endl;
    #define endl '
    '
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    // mt19937 rnd(TM(0));
    const int inf = 0x3f3f3f3f;//1061109567 > 1e9
    const ll linf = 0x3f3f3f3f3f3f3f3f;
    const double eps = 1e-6;
    const double pi = 3.14159265358979;
    const int maxn = 3e6 + 5;
    const int maxm = 1e7 + 233;
    const int mod = 1e9 + 7;
    
    ll n, l, r, a[maxn];
    struct edge
    {
        int to, nxt; ll w;
    }edge[maxn << 1];
    int tot, head[maxn << 1];
    void init()
    {
        tot = 0;
        memset(head, -1, sizeof head);
    }
    void addedge(int u, int v, ll w)
    {
        edge[tot].to = v;
        edge[tot].w = w;
        edge[tot].nxt = head[u];
        head[u] = tot++;
    }
    struct node
    {
        int v; ll w;
        node(){}
        node(int _v, ll _w):v(_v), w(_w){}
        const bool operator<(const node &r)const{
            return w > r.w;
        }
    }tmp;
    ll dis[maxn];
    bool vis[maxn];
    void dijkstra(int s)
    {
        memset(dis, inf, sizeof dis);
        memset(vis, false, sizeof vis);
        priority_queue<node> q;
        while(!q.empty())q.pop();
        q.push(node(s, 0));
        dis[s] = 0;
        while(!q.empty())
        {
            tmp = q.top(); q.pop();
            if(vis[tmp.v])continue;
            vis[tmp.v] = true;
            for(int i = head[tmp.v]; ~i; i = edge[i].nxt)
            {
                int v = edge[i].to;
                if(dis[v] > dis[tmp.v] + edge[i].w)
                {
                    dis[v] = dis[tmp.v] + edge[i].w;
                    q.push(node(v, dis[v]));
                }
            }
        }
    }
    int main()
    {
        // double pp = clock();
        // freopen("233.in", "r", stdin);
        // freopen("233.out", "w", stdout);
        ios_base::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        
        cin >> n >> l >> r;
        for(int i = 1; i <= n; ++i)cin >> a[i];
        sort(a + 1, a + 1 + n);
        int mi = a[1];
        init();
        for(int i = 0; i <= mi - 1; ++i)
            for(int j = 1; j <= n; ++j)
                addedge(i, (i + a[j]) % mi, a[j]);
        dijkstra(0);
        ll ans = 0;
        for(int i = 0; i <= mi - 1; ++i)
        {
            if(dis[i] <= r)
            {
                if(dis[i] == 0)dis[i] = mi;
                ans += (r - dis[i]) / mi + 1;
                if(l > dis[i])ans -= (l - dis[i] - 1) / mi + 1;
            }
        }
        cout << ans << endl;
    
        return 0;
    }
    

    P3403 跳楼机

    题目

    比上面那个简单些,,就是注意细节,,从1开始,,有一个是1那么值一定是h,,,

    #include <bits/stdc++.h>
    #define aaa cout<<233<<endl;
    #define endl '
    '
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    // mt19937 rnd(TM(0));
    const int inf = 0x3f3f3f3f;//1061109567 > 1e9
    const ll linf = 0x3f3f3f3f3f3f3f3f;
    const double eps = 1e-6;
    const double pi = 3.14159265358979;
    const int maxn = 3e6 + 5;
    const int maxm = 1e7 + 233;
    const int mod = 1e9 + 7;
    
    ll n, l, r, a[maxn];
    struct edge
    {
        int to, nxt; ll w;
    }edge[maxn << 1];
    int tot, head[maxn << 1];
    void init()
    {
        tot = 0;
        memset(head, -1, sizeof head);
    }
    void addedge(int u, int v, ll w)
    {
        edge[tot].to = v;
        edge[tot].w = w;
        edge[tot].nxt = head[u];
        head[u] = tot++;
    }
    struct node
    {
        int v; ll w;
        node(){}
        node(int _v, ll _w):v(_v), w(_w){}
        const bool operator<(const node &r)const{
            return w > r.w;
        }
    }tmp;
    ll dis[maxn];
    bool vis[maxn];
    void dijkstra(int s)
    {
        memset(dis, inf, sizeof dis);
        memset(vis, false, sizeof vis);
        priority_queue<node> q;
        while(!q.empty())q.pop();
        q.push(node(s, 0));
        dis[s] = 1;
        while(!q.empty())
        {
            tmp = q.top(); q.pop();
            if(vis[tmp.v])continue;
            vis[tmp.v] = true;
            for(int i = head[tmp.v]; ~i; i = edge[i].nxt)
            {
                int v = edge[i].to;
                if(dis[v] > dis[tmp.v] + edge[i].w)
                {
                    dis[v] = dis[tmp.v] + edge[i].w;
                    q.push(node(v, dis[v]));
                }
            }
        }
    }
    int main()
    {
        // double pp = clock();
        // freopen("233.in", "r", stdin);
        // freopen("233.out", "w", stdout);
        ios_base::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        
        cin >> n;
        for(int i = 1; i <= 3; ++i)cin >> a[i];
        sort(a + 1, a + 1 + 3);
        if(a[1] == 1){
            cout << n << endl;
            return 0;
        }
        ll mi = a[1];
        init();
        for(int i = 0; i <= mi - 1; ++i)
            for(int j = 2; j <= 3; ++j) 
                addedge(i, (i + a[j]) % mi, a[j]);
        dijkstra(1);
        ll ans = 0;
        for(int i = 0; i <= mi - 1; ++i)
            if(dis[i] <= n)
                ans += (n - dis[i]) / mi + 1;
        cout << ans << endl;
    
        return 0;
    }
    

    遥远的旅途

    题目

    这题的大致思路是将dp问题用最短路来优化,,

    dp[i][j] 表示从起点走到i时的长度为j的一条路是否存在,,但是空间都会爆掉,,

    考虑第二维,假设是通过经过若干个环来达到T,,也就是 len+kw==T ,,这里的w即为环的长度的两倍,,如果取模w就是 len%w==T%w ,,这样子dp方程就变成了到达 i 点时路径长度取模等于j的一条路径的长度,,利用spfa来转移,,只要最后 dp[n][T%w] <= T 就表示存在解,这样子利用模数来压缩了状态,,找等同的就行了,,,参考 参考

    #include <bits/stdc++.h>
    #define aaa cout<<233<<endl;
    #define endl '
    '
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef long double ld;
    // mt19937 rnd(TM(0));
    const int inf = 0x3f3f3f3f;//1061109567 > 1e9
    const ll linf = 0x3f3f3f3f3f3f3f3f;
    const double eps = 1e-6;
    const double pi = 3.14159265358979;
    const int maxn = 1e2 + 5;
    const int maxm = 1e7 + 233;
    const int mod = 1e9 + 7;
    
    ll n, m, T, a[maxn], ww;
    struct edge
    {
        int to, nxt; ll w;
    }edge[maxn << 1];
    int tot, head[maxn << 1];
    void init()
    {
        tot = 0;
        memset(head, -1, sizeof head);
    }
    void addedge(int u, int v, ll w)
    {
        edge[tot].to = v;
        edge[tot].w = w;
        edge[tot].nxt = head[u];
        head[u] = tot++;
    }
    ll dp[maxn][20005];
    bool vis[maxn][20005];
    queue<pair<int, ll> > q;
    void spfa()
    {
        memset(dp, inf, sizeof dp);
        memset(vis, false, sizeof vis);
        while(!q.empty())q.pop();
        dp[1][0] = 0; vis[1][0] = true;
        q.push(make_pair(1, 0));
        while(!q.empty())
        {
            int u = q.front().first; ll w = q.front().second; q.pop(); 
            vis[u][w] = false;
            for(int i = head[u]; ~i; i = edge[i].nxt)
            {
                int v = edge[i].to; ll vw = edge[i].w;
                if(dp[v][(w + vw) % ww] > dp[u][w] + vw)
                {
                    dp[v][(w + vw) % ww] = dp[u][w] + vw;
                    if(!vis[v][(w + vw) % ww])
                    {
                        vis[v][(w + vw) % ww] = true;
                        q.push(make_pair(v, (w + vw) % ww));
                    }
                }
            }
        }
    }
    int main()
    {
        // double pp = clock();
        // freopen("233.in", "r", stdin);
        // freopen("233.out", "w", stdout);
        ios_base::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        
        int t; cin >> t;
        while(t--)
        {
            cin >> n >> m >> T;
            int u, v, w;
            init();
            for(int i = 1; i <= m; ++i)
            {
                cin >> u >> v >> w;
                ++u, ++v;
                addedge(u, v, w);
                addedge(v, u, w);
            }
            bool flag = false;
            for(int i = head[n]; ~i; i = edge[i].nxt)
            {
                ww = edge[i].w << 1;
                spfa();
                if(dp[n][T % ww] <= T)
                {
                    flag = true;
                    break;
                }
            }
            if(flag)cout << "Possible" << endl;
            else cout << "Impossible" << endl;
        }
    
        return 0;
    }
    

    (end)

  • 相关阅读:
    MyBatis配置文件(四)--typeHandlers
    MyBatis配置文件(三)--typeAliases别名
    理解JWT的使用场景和优劣
    JWT的使用流程
    JWT (JSON WEB Token)正确使用场景
    转 Spring Security 简介
    转 Solr vs. Elasticsearch谁是开源搜索引擎王者
    Oauth2.0(一):为什么需要 Oauth2.0 协议?
    Spring Security 与 OAuth2(介绍)
    理解OAuth 2.0
  • 原文地址:https://www.cnblogs.com/31415926535x/p/11692422.html
Copyright © 2011-2022 走看看