Blue Book 上的图论T(未完成)

Sorting It All Out:

对于可以得到绝对顺序的图,拓扑排序可以直接确定顺序
如果拓扑排序没能遍历所有的点,就说明存在一个环。
set也可以用count,我为什么才知道

Sightseeing trip:(无向图的最小环问题):

考虑一个图中的最小环u->v->k->u,如果我们随意去掉其中一条边u->v
那么剩下的v->k->u一定是图中u->v建的最短路径
在Floyed算法枚举k的时候,已经得到了前k-1个点的最短路径,这k-1个点不包括k,并且他们的最短路径中也不包括k点
由对称性可知,这样做并不会影响结果

走廊泼水节;(https://www.acwing.com/problem/content/348/)

又是熟悉的感觉?有一个题是完全图最短路,开始边权相同,后来有修改,修改只涉及了最多6000个点,就把修改的拿出来
好像是多校里的某个T4->欢乐豆,这种取出某些点单独最短路的套路可以应用到[最短路问题V3]
为了保证(x, y)一定在最小生成树中,就必须让(x, y)是连接集合Sx与Sy的权值最小的边,因此(u, v)的权值应该定为w(x, y)+1
求增加的边的权值,从原有的边里找

Picnic Planning:(https://www.acwing.com/problem/content/349/)

书看了一半,以为拆出来连通块之后问题就完美解决,然后被后半部分吓到了
鹤完文字版就鹤code
没有作者的高级题意转化还真不容易想到最小生成树,关于映射也有一点细节
口胡很容易但是对鹤就不太友好。。
Star way to heven 好像也是一道用prim跑最小生成树的题,很少用prim还是很不熟练
忽然发现也不是必须用prim。。

code
#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 1005;
const int inf = 0x7fffffff;

int n, tot, k, mpcnt;
map<string, int> mp;
const string park = "Park";

inline int read()
{
    int x = 0, f = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
        if(ch == '-')
        {
            f = -1;
        }
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        x = (x << 1) + (x << 3) + (ch^48);
        ch = getchar();
    }
    return x * f;
}

struct Build_graph 
{
    int mp[maxn][maxn]; bool link[maxn][maxn];
    inline void _add(int u, int v, int w) {link[u][v] = link[v][u] = true; mp[u][v] = mp[v][u] = w;}
    inline void _cut(int u, int v) {link[u][v] = link[v][u] = false; mp[u][v] = mp[v][u] = inf;}
    inline void init(int n)
    {
        for(int i=1; i<=n; i++) for(int j=1; j<=n; j++)
        {
            link[i][j] = false; mp[i][j] = inf;
        }
    }
}Old;

struct Kruskal 
{
    struct edge 
    {
        int a, b, v;
        bool operator < (const edge &T) const 
        {
            return v > T.v;
        }
    };
    priority_queue<edge> q;
    int v0, tree_num, ans;
    int f[maxn], Minn_dis[maxn], Minn_id[maxn];

    Kruskal():tree_num(0), ans(0){}
    void addEdge(int x, int y, int v)
    {
        q.push({x, y, v});
    }
    int find(int x)
    {
        if(f[x] == x) return x;
        return f[x] = find(f[x]);
    }
    void init(int n)
    {
        tree_num = 0; ans = 0;
        for(int i=1; i<=n; i++)
        {
            f[i] = i; Minn_id[i] = i;
            Minn_dis[i] = inf;
        }
        while(!q.empty()) q.pop();
    }
    int kruskal(int n)
    {
        int ret = 0;
        while(!q.empty())
        {
            edge now = q.top(); q.pop();
            int fa = find(now.a), fb = find(now.b);
            if(now.a == v0)//这时fb一定要并到fa上,每一条边都算数
            {
                if(Minn_dis[fb] > now.v) {Minn_dis[fb] = now.v; Minn_id[fb] = now.b;}
            }
            else if(now.b == v0)
            {
                if(Minn_dis[fa] > now.v) {Minn_dis[fa] = now.v; Minn_id[fa] = now.a;}
            }
            else 
            {
                if(fa != fb)
                {
                    ret += now.v;
                    f[fa] = fb;
                    if(Minn_dis[fa] < Minn_dis[fb])
                    {
                        Minn_dis[fb] = Minn_dis[fa]; Minn_id[fb] = Minn_id[fa];
                    }
                    Old._add(now.a, now.b, now.v);
                }
            }
        }
        //先删掉v0,再从v0向每一个删掉它得到的连通块连一条边
        for(int i=1; i<=n; i++)
        {
            if(i == v0) continue;
            if(find(i) == i)
            {
                ret += Minn_dis[i];
                tree_num++;
                Old._add(v0, Minn_id[i], Minn_dis[i]);
            }
        }
        ans = ret;
        return ret;
    }
}a;

struct K_limit_tree 
{
    struct DP 
    {
        int id, fa, dis;
        DP(int a=0, int c=0, int b=0):id(a), fa(c), dis(b){}
        friend bool operator < (DP e1, DP e2) {return e1.dis < e2.dis;}
    }dp[maxn];

    struct V0 {int v, w;};
    vector<V0> v0link;
    int v0;

    void dfs(int u, int fa, const int n)
    {
        for(int i=1; i<=n; i++)
        {
            if(i == v0) continue;
            if(Old.link[u][i] && (i^fa))
            {
                //每个点到v0最短路径上的权值最大的边dp[i]
                dp[i] = max(DP(i, u, Old.mp[u][i]), dp[u]);
                dfs(i, u, n);
            }
        }
    }
    void solve(Kruskal &kru, int K, const int n)
    {
        v0 = kru.v0;
        dfs(kru.v0, 0, n);
        int len = v0link.size();
        //本来应该从+1开始的,现在让K-1也是等效
        for(int tims=kru.tree_num,maxx_det,id; tims<K; tims++)
        {
            maxx_det = -inf; id = -1;
            for(int i=0; i<len; i++)
            {
                if(dp[v0link[i].v].dis-v0link[i].w > maxx_det && !Old.link[kru.v0][v0link[i].v])
                {
                    maxx_det = dp[v0link[i].v].dis - v0link[i].w;
                    id = i;
                }
            }
            if(maxx_det <= 0) break;
            kru.ans -= maxx_det;
            Old._add(kru.v0, v0link[id].v, v0link[id].w);
            Old._cut(dp[v0link[id].v].id, dp[v0link[id].v].fa);
            dfs(kru.v0, 0, n);
        }
    }
}b;

void init(int n, int v0)
{
    Old.init(n); b.dp[v0] = {v0, 0, 0};
    for(int i=1; i<=n; i++)
    {
        a.f[i] = i; a.Minn_id[i] = i;
        a.Minn_dis[i] = inf;
    }
}

int main()
{
    n = read();
    for(int i=1; i<=n; i++)
    {
        string s1, s2; int v;
        cin >> s1 >> s2 >> v;
        if(mp[s1] == 0) {mp[s1] = ++mpcnt;}
        if(mp[s2] == 0) {mp[s2] = ++mpcnt;}
        int x = mp[s1], y = mp[s2];
        a.addEdge(x, y, v);
        if(x == mp[park]) {b.v0link.push_back({y, v});}
        else if(y == mp[park]) {b.v0link.push_back({x, v});}
    }
    init(mpcnt, mp[park]);
    a.v0 = mp[park];
    cin >> k;
    tot = a.kruskal(mpcnt);
    b.solve(a, k, mpcnt);
    printf("Total miles driven: %d\n", a.ans);

    return 0;
}
posted @ 2022-10-28 07:09  Catherine_leah  阅读(11)  评论(0编辑  收藏  举报
/* */