zoukankan      html  css  js  c++  java
  • E

    题意:给你一张无向图,无重边无自环。给出定义:对于一条路径(不一定是简单路径,比如对于图(1-2-3,1->2->3->2)这种有些边走了2次的就不是简单路径),他的路径总权值为路径上每一条经过边的和减去路径上最大的边权加上路径上最小的边权。让你求1点到每个点的最小满足上述条件的路径权值。

    做法:由于不知道从1到某一点的路径究竟是怎么样的(不知道经过哪些点,不知道最大最小值,不知道是否为简单路径。。。)。但这条路径中只有一个最大值和一个最小值,对于某一条边我们可以得到4个状态:

    ①这条边即不是最大值也不是最小值。

    ②这条边是最大值

    ③这条边是最小值

    ④这条边即是最大值也是最小值

    这样可以用类似dp的方法,通过将图分层,把所有可行状态枚举出来去更新每个点的答案。


    代码有两种写法:

    一:dis分层

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
    const ll inf = 1e18 + 7;
    const int maxn = 2e5 + 10;
    
    struct Node {
        ll dis;
        int from, v1, v2;
        friend bool operator <(Node x, Node y){
            return x.dis > y.dis;
        }
    };
    
    int head[maxn], edge_cnt = 0;
    
    struct edge {
        int to;
        ll cost;
        int next;
    }e[maxn << 1];
    
    void add(int from, int to, ll cost)
    {
        e[++edge_cnt] = { to,cost,head[from] };
        head[from] = edge_cnt;
    }
    
    ll dis[maxn][2][2];
    int n;
    void dij()
    {
        priority_queue<Node>q;
        for (int i = 1; i <= n; i++)
            for (int j = 0; j <= 1; j++)
                for (int k = 0; k <= 1; k++)
                    dis[i][j][k] = inf;
        q.push({ 0,1,0,0 });
        while (!q.empty())
        {
            Node now = q.top();
            q.pop();
            int from = now.from; ll dist = now.dis;
            bool v1 = now.v1, v2 = now.v2;
            if (now.dis > dis[from][v1][v2])continue;
            for (int i = head[from]; ~i; i = e[i].next)
            {
                int to = e[i].to; ll cost = e[i].cost;
                if (dis[to][v1][v2] > dist + cost)
                {
                    dis[to][v1][v2] = dist + cost;
                    q.push({ dis[to][v1][v2],to,v1,v2 });
                }
                if (!v1 && dis[to][1][v2] > dist)
                {
                    dis[to][1][v2] = dist;
                    q.push({ dis[to][1][v2],to,1,v2 });
                }
                if (!v2 && dis[to][v1][1] > dist + 2 * cost)
                {
                    dis[to][v1][1] = dist + 2 * cost;
                    q.push({ dis[to][v1][1],to,v1,1 });
                }
                if (!v1 && !v2 && dis[to][1][1] > dist + cost)
                {
                    dis[to][1][1] = dist + cost;
                    q.push({ dis[to][1][1],to,1,1 });
                }
            }
        }
        for (int i = 2; i <= n; i++)
            cout << dis[i][1][1] << " ";
    }
    
    int main()
    {
    	//freopen("C:\test.txt", "r", stdin);
        fastio;
        memset(head, -1, sizeof(head));
        int m;
        cin >> n >> m;
        while (m--)
        {
            int x, y, z;
            cin >> x >> y >> z;
            add(x, y, z);
            add(y, x, z);
        }
        dij();
    
        return 0;
    
    }
    
    

    二:开4倍的点

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define fastio ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL)
    const ll inf = 1e18 + 7;
    const int maxn = 2e5 + 10;
    
    struct Node {
        ll dis;
        int from;
        friend bool operator <(Node x, Node y){
            return x.dis > y.dis;
        }
    };
    
    int head[4 * maxn], edge_cnt = 0;
    
    struct edge {
        int to;
        ll cost;
        int next;
    }e[maxn * 18 + 1];
    
    void add(int from, int to, ll cost)
    {
        e[++edge_cnt] = { to,cost,head[from] };
        head[from] = edge_cnt;
    }
    
    ll dis[4*maxn];
    int n;
    void dij()
    {
        priority_queue<Node>q;
        for (int i = 1; i <= 4 * n; i++)
                    dis[i] = inf;
        dis[1] = 0;
        q.push({ 0,1});
        while (!q.empty())
        {
            Node now = q.top();
            q.pop();
            int from = now.from; ll dist = now.dis;
            if (now.dis > dis[from])continue;
            for (int i = head[from]; ~i; i = e[i].next)
            {
                int to = e[i].to; ll cost = e[i].cost;
                if (dis[to] > dist + cost)
                {
                    dis[to] = dist + cost;
                    q.push({ dis[to],to});
                }
            }
        }
        for (int i = 3 * n + 2; i <= 4 * n; i++)
            cout << dis[i] << " ";
    }
    
    int main()
    {
    	//freopen("C:\test.txt", "r", stdin);
        fastio;
        memset(head, -1, sizeof(head));
        int m;
        cin >> n >> m;
        while (m--)
        {
            int x, y, z;
            cin >> x >> y >> z;
            add(x, y, z);
            add(y, x, z);
            add(x + n, y + n, z);
            add(y + n, x + n, z);
            add(x + 2 * n, y + 2 * n, z);
            add(y + 2 * n, x + 2 * n, z);
            add(x + 3 * n, y + 3 * n, z);
            add(y + 3 * n, x + 3 * n, z);
            add(x, y + n, 0);
            add(y, x + n, 0);
            add(x, y + 2 * n, 2 * z);
            add(y, x + 2 * n, 2 * z);
            add(x, y + 3 * n, z);
            add(y, x + 3 * n, z);
            add(x + n, y + 3 * n, 2 * z);
            add(y + n, x + 3 * n, 2 * z);
            add(x + 2 * n, y + 3 * n, 0);
            add(y + 2 * n, x + 3 * n, 0);
    
        }
        dij();
    
        return 0;
    
    }
    
    
  • 相关阅读:
    poj 3528 (三维几何求凸包+凸包表面积)
    dijkstra模板(好像是斐波那契额堆优化,但我为什么看起来像优先队列优化,和spfa一样)
    最大空凸包模板
    ICPC 2017–2018, NEERC, Northern Subregional Contest St Petersburg, November 4, 2017 I题
    hdu 5248 序列变换
    hdu 2063(二分图模板测试)
    组合数
    85. Maximal Rectangle 由1拼出的最大矩形
    750. Number Of Corner Rectangles四周是点的矩形个数
    801. Minimum Swaps To Make Sequences Increasing 为使两个数组严格递增,所需要的最小交换次数
  • 原文地址:https://www.cnblogs.com/ruanbaiQAQ/p/14284425.html
Copyright © 2011-2022 走看看