NOIP2013货车运输(最大生成树+LCA)

货车运输这道题我觉得还是比较有难度,不好直接想出正解,我最开始就是直接用并查集判定然后暴力找,在网上只有10分。

//以下是暴力

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 10005
#define MAXM 50005
#define MAXP 30005
inline void GET(int &n)
{
    n = 0; char c;
    do c = getchar(); while(c > '9' || c < '0');
    while(c>='0' && c<='9'){n = n * 10 + c - '0'; c = getchar();}
}
struct P
{
    int s, t, i;
    bool operator < (const P rhs) const
    {
        return s < rhs.s;
    }
}op[MAXP];
struct node
{
    int v, w;
    node *next;
}Edge[MAXN*2], *Adj[MAXN], *Mcnt = Edge;
void Addedge(int u, int v, int w)
{
    node *t = ++Mcnt;
    t->v = v;
    t->w = w;
    t->next = Adj[u];
    Adj[u] = t;
}
int fa[MAXN], w[MAXN], n, m, p, ans[MAXP];
int rt(int x)
{
    if(fa[x] && fa[x] != x) return fa[x] = rt(fa[x]);
    return x;
}
void dfs(int u, int c)
{
    w[u] = c;
    int C;
    for(node *p = Adj[u]; p; p = p->next)
    {
        C = min(p->w, c);
        if(w[p->v] < C) dfs(p->v, C);
    }
}
int main()
{
    int t1, t2, t3;
    GET(n);GET(m);
    for(int i = 1; i <= m; i ++)
    {
        GET(t1);GET(t2);GET(t3);
        Addedge(t1, t2, t3);
        Addedge(t2, t1, t3);
        if(rt(t1) != rt(t2) || rt(t1) == 0)fa[rt(t1)] = rt(t2);
    }
    GET(p);
    for(int i = 1; i <= p; i ++)
    {
        GET(t1);GET(t2);
        op[i].s = min(t1, t2);
        op[i].t = max(t1, t2);
        op[i].i = i;
    }
    sort(op + 1, op + p + 1);
    int pre = -1;
    for(int i = 1; i <= p; i ++)
    {
        if(rt(op[i].s) != rt(op[i].t))
        {
            ans[op[i].i] = -1;
            continue;
        }
        if(pre != op[i].s)
        {
            memset(w, -1, sizeof w);
            w[op[i].s] = 0x7f7f7f7f;
            dfs(op[i].s, 0x7f7f7f7f);
            pre = op[i].s;
        }
        ans[op[i].i] = w[op[i].t];
    }
    for(int i = 1; i <= p; i ++)
        printf("%d\n", ans[i]);
    return 0;
}

后来才知道要用最大生成树去掉没有价值的边,然后我又写了一个最大生成树+暴力找路径最小边的,得到了30分

#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 10005
#define MAXM 50005
#define MAXP 30005
inline void GET(int &n)
{
    n = 0; char c;
    do c = getchar(); while(c > '9' || c < '0');
    while(c>='0' && c<='9'){n = n * 10 + c - '0'; c = getchar();}
}
struct P
{
    int s, t, v;
    bool operator < (const P rhs) const
    {
        return v > rhs.v;
    }
}a[MAXP];
struct node
{
    int v, w;
    node *next;
}Edge[MAXN*2], *Adj[MAXN], *Mcnt = Edge;
void Addedge(int u, int v, int w)
{
    node *t = ++Mcnt;
    t->v = v;
    t->w = w;
    t->next = Adj[u];
    Adj[u] = t;
}
int fa[MAXN], n, m, p;
int rt(int x)
{
    if(fa[x] && fa[x] != x) return fa[x] = rt(fa[x]);
    return x;
}
bool vis[MAXN][2];
int w[MAXN];
struct Y
{
    int a;
    bool f;
    Y(){}
    Y(int b,bool g){a = b; f = g;}
};
int BFS(int r1, int r2)
{
    queue<Y> q;
    q.push(Y(r1, 0));
    q.push(Y(r2, 1));
    memset(w, 0, sizeof w);
    memset(vis, 0, sizeof vis);
    vis[r1][0] = vis[r2][1] = 1;
    w[r1] = w[r2] = 0x7f7f7f7f;
    while(!q.empty())
    {
        int u = q.front().a;
        bool f = q.front().f;
        q.pop();
        for(node *p = Adj[u]; p; p = p->next)
        {
            if(!vis[p->v][f])
            {
                if(vis[p->v][!f]) return min(min(w[p->v], w[u]), p->w);
                w[p->v] = min(w[u], p->w);
                q.push(Y(p->v, f));
                vis[p->v][f] = 1;
            }
        }
    }
    return -1;
}
int main()
{
    int t1, t2, t3;
    GET(n);GET(m);
    for(int i = 1; i <= m; i ++)
    {
        GET(t1);GET(t2);GET(t3);
        a[i].s = t1, a[i].t = t2, a[i].v = t3;
    }
    sort(a+1, a+m+1);
    int tot = 0;
    for(int i = 1; i <= m; i ++)
    {
        t1 = a[i].s, t2 = a[i].t, t3 = a[i].v;
        int p = rt(t1), q = rt(t2);
        if(p != q){
            fa[p] = q;
            Addedge(t1, t2, t3);
            Addedge(t2, t1, t3);
            tot ++;
            if(tot == n - 1) break;
        }
    }
    GET(p);
    for(int i = 1; i <= p; i ++)
    {
        GET(t1);GET(t2);
        int p = rt(t1), q = rt(t2);
        if(p != q){puts("-1");continue;}
        int tp = BFS(t1, t2);
        printf("%d\n", tp);
    }
    return 0;
}

过后,对于每一个连通块用dfs把无根树变成了有根树就非常快了,得分100,耗时44ms

#include<cstdio>
#include<ctime>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 10005*2
#define MAXM 50005*2
#define MAXP 30005*2
inline int min(const int &a, const int &b){return a<b?a:b;}

inline void GET(int &n)
{
    n = 0; char c;
    do c = getchar(); while(c > '9' || c < '0');
    while(c>='0' && c<='9'){n = n * 10 + c - '0'; c = getchar();}
}
struct P
{
    int s, t, v;
    bool operator < (const P rhs) const
    {
        return v > rhs.v;
    }
}a[MAXP];
struct node
{
    int v, w;
    node *next;
}Edge[MAXN*2], *Adj[MAXN], *Mcnt = Edge;
void Addedge(int u, int v, int w)
{
    node *t = ++Mcnt;
    t->v = v;
    t->w = w;
    t->next = Adj[u];
    Adj[u] = t;
}
int fa[MAXN], n, m, p;
int rt(int x)
{
    if(fa[x] && fa[x] != x) return fa[x] = rt(fa[x]);
    return x;
}
int pre[MAXN], dep[MAXN], v[MAXN];
bool vis[MAXN];
void dfs(int u)
{
    vis[u] = 1;
    for(node *p = Adj[u]; p; p = p->next)
        if(!vis[p->v])
        {
            pre[p->v] = u;
            v[p->v] = p->w;
            dep[p->v] = dep[u] + 1;
            dfs(p->v);
        }
}
int Val(int t1, int t2)
{
    int mn1 = 0x7f7f7f7f, mn2 = 0x7f7f7f7f;
    if(dep[t1] < dep[t2]) swap(t1, t2);
    while(dep[t1] > dep[t2])
    {
        mn1 = min(mn1, v[t1]);
        t1 = pre[t1];
    }
    while(t1 != t2)
    {
        mn1 = min(mn1, v[t1]);
        t1 = pre[t1];
        mn2 = min(mn2, v[t2]);
        t2 = pre[t2];
    }
    return min(mn1, mn2);
}
int main()
{
    int t1, t2, t3;
    GET(n);GET(m);
    for(int i = 1; i <= m; i ++)
    {
        GET(t1);GET(t2);GET(t3);
        a[i].s = t1, a[i].t = t2, a[i].v = t3;
    }
    sort(a+1, a+m+1);
    int tot = 0;
    for(int i = 1; i <= m; i ++)
    {
        t1 = a[i].s, t2 = a[i].t, t3 = a[i].v;
        int p = rt(t1), q = rt(t2);
        if(p != q){
            fa[p] = q;
            Addedge(t1, t2, t3);
            Addedge(t2, t1, t3);
            tot ++;
            if(tot == n - 1) break;
        }
    }
    GET(p);
    for(int i = 1; i <= n; i ++)
        if(!vis[i])
            dfs(i);
    for(int i = 1; i <= p; i ++)
    {
        GET(t1);GET(t2);
        int p = rt(t1), q = rt(t2);
        if(p != q){puts("-1");continue;}
        int tp = Val(t1, t2);
        printf("%d\n", tp);
    }
    return 0;
}

你可能感兴趣的:(NOIP2013货车运输(最大生成树+LCA))