列表

详情


NC51365. PKU ACM Team's Excursions

描述

给定一张 N 个点 M 条边的有向无环图,点的编号从 0 到 N - 1,每条边都有一个长度。

给定一个起点 S 和一个终点 T。

若从 S 到 T 的每条路径都经过某条边,则称这条边是有向图的必经边或桥。

北大 ACM 队要从 S 点到 T 点。

他们在路上可以搭乘两次车。

每次可以从任意位置(甚至是一条边上的任意位置)上车,从任意位置下车,但连续乘坐的长度不能超过 q 米。

除去这两次乘车外,剩下的路段步行。

定义从 S 到 T 的路径的危险程度等于步行经过的桥上路段的长度之和。

求从 S 到 T 的最小危险程度是多少。

输入描述

第一行包含整数 L,表示共有 L 组测试数据。
每组测试数据,第一行包含五个整数 N,M,S,T,q 。
接下来 M 行,每行包含三个整数u,v,w,表示点 u 到点 v 存在一条边,长度为 w。

输出描述

每组数据输出一个结果,每个结果占一行。
若没有从 S 到 T 的路径,则输出 -1。

示例1

输入:

1
8 9 0 7 7
0 4 1
0 1 10
1 2 9
4 2 2
2 5 8
4 3 3
5 6 6
5 6 7
6 7 5

输出:

1

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C(clang 3.9) 解法, 执行用时: 532ms, 内存消耗: 11640K, 提交时间: 2020-07-23 00:36:03

#include <stdio.h>
#include <stdbool.h>
#include <string.h>

#define V  100000
#define p 1000000021

typedef struct{
    int head, indeg,dp;
}Vertex;


typedef struct {
    int to,next, w,isbridge; 
}Edge;

const Vertex NEUTRAL_VERTEX = {-1,0,0};
const Edge   NEUTRAL_EDGE = {0,-1,0, 1};

int eid,eid2;
int n,m,s,t,q;

Vertex v[V], v2[V];
Edge   e[2*V], e2[2*V];

int max(int a,int b) {
    return a > b ? a : b;
}

void init(int n,int m) {
    eid = eid2 = 0;
    for(int i=0;i<n;i++) v[i] = v2[i] = NEUTRAL_VERTEX;
}   

void add(int x,int y,int w) {
    e[eid] = (Edge){ y, v[x].head, w, 1  };
    v[x].head = eid++;
    v[y].indeg++;   
}

void add2(int x,int y,int w) {
    e2[eid2] =  (Edge){ y, v2[x].head, w, 1  };
    v2[x].head = eid2++;
    v2[y].indeg++;
}

int Q[V],Qsz, indeg[V];

void cal_fs(int s,int n, const Vertex *v, Edge *e, int M,int *fs) {
    for(int i=0;i<n;i++) fs[i] = 0;
    fs[s] = 1;
    Qsz = 0;

    for(int i=0;i<n;i++) {
        indeg[i] = v[i].indeg;
        if(indeg[i]==0) Q[Qsz++] = i;
    }

    int x,y;
    for(int qi=0;qi<Qsz;qi++) {
        x = Q[qi];
        for(int i = v[x].head; ~i; i = e[i].next ) {
            y = e[i].to;
            fs[y] = ( fs[y] + fs[x] ) % M;
            if(--indeg[y]==0) Q[Qsz++] = y;
        }
    }
}

int dist[V],prev[V],pree[V],path[V], psz;

void cal_ds(int s, int t ,Vertex *v, const Edge *e) {
    memset(dist,0x3f3f3f3f,sizeof(dist));
    dist[s] = 0;
    Qsz = 0;
    for(int i=0;i<n;i++) if(v[i].indeg==0) Q[Qsz++] = i;
    for(int qi = 0; qi<Qsz;qi++) {
        int x = Q[qi];
        for(int i = v[x].head; ~i; i = e[i].next) {
            int y = e[i].to;
            if(dist[x] + e[i].w < dist[y]) {
                dist[y] = dist[x] + e[i].w;
                pree[y] = i;
                prev[y] = x;
            }
            if(--v[y].indeg==0) Q[Qsz++] = y;
        }
    }
    psz = 0;

    int z = t;
    while(z!=s) {
        path[psz++] = pree[z];
        z = prev[z];
    }

    int temp;
    for(int i=0;i<psz/2;i++) {
        temp = path[i];
        path[i] = path[psz-1-i];
        path[psz-1-i] = temp;
    }

    int j = 0, len = 0, B = 0, best = 0;
    for(int k = 0;k<psz;k++) {
        int i = path[k];
        int to = e[i].to;
        len += e[i].w;
        if(e[i].isbridge) B += e[i].w;

        while(len>q) {

            len -= e[path[j]].w;
            if(e[path[j]].isbridge) B -= e[path[j]].w;
            j++;

        }
        v[to].dp = B;
        if(j>0 && e[path[j-1]].isbridge) v[to].dp += q-len;
        v[to].dp = max(v[to].dp, best);
        best = max(best,v[to].dp);

        //printf("best = %d, i = %d, e[i].w = %d, to = %d, v[to].dp = %d\n",best, i, e[i].w, to, v[to].dp);

    }
} 

int fs[V],ft[V];

int main() {
    int tt; scanf("%d",&tt);
    while(tt--) {
        scanf("%d%d%d%d%d",&n,&m,&s,&t,&q);
        
        init(n,m);
        for(int i=0;i<m;i++) {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            if(u==v) continue;
            add(u,v,w);
            add2(v,u,w);
        }
        cal_fs(s,n,v,e,p,fs);
        cal_fs(t,n,v2,e2,p,ft);

        for(int x = 0; x < n; x++) {
            for(int i = v[x].head; ~i; i = e[i].next) {
                int y = e[i].to;
                if( 1ll * fs[x] * ft[y] % p != fs[t]) e[i].isbridge = 0;
            }
            for(int i=v2[x].head; ~i; i=e2[i].next) {
                int y = e2[i].to;
                if(1ll*ft[x]*fs[y]%p != ft[s]) e2[i].isbridge = 0;
            }
        }

        cal_ds(s,t,v,e);
        cal_ds(t,s,v2,e2);

        int ans = 0, temp = 0;
        for(int i=0;i<m;i++) {
            if(e[i].isbridge) {
                ans += e[i].w;
            }
        }
        
        for(int i=0;i<n;i++) {
            temp = max(temp, v[i].dp + v2[i].dp);
        }
        printf("%d\n",ans-temp);
    }
    return 0;
}

C++14(g++5.4) 解法, 执行用时: 411ms, 内存消耗: 26904K, 提交时间: 2020-09-23 23:11:50

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <cstring>

using namespace std;

typedef long long LL;
const int N = 1e5+5,M = 2*N,inf = 0x3f3f3f3f,mod = 1e9 + 7;

int tot,S,T,n,m,q,idx = 1,ver[M],wet[M],nxt[M],head[N],dis[N],indu[N],edu[M],edv[M],edw[M],pre[N];
queue<int> q1;
bool bridge[M];
LL dt[N],ds[N],cnt1[N],cnt2[N],sum_b[N],sum[N];

void add(int u,int v,int w)
{
    nxt[++idx] = head[u];
    ver[idx] = v;
    wet[idx] = w;
    head[u] = idx;
}

void bfs(int st,LL a[])
{
    memset(dis,inf,sizeof dis);
    a[st] = 1;
    q1.push(st);
    dis[st] = 0;

    while(q1.size())
    {
        int u = q1.front();q1.pop();
        for(int i = head[u]; i ;i = nxt[i])
        {
            int v = ver[i];
            indu[v] --;
            if(!indu[v])q1.push(v);
            a[v] = (a[u] + a[v]) % mod;
            if(dis[v] > dis[u] + wet[i])
                dis[v] = dis[u] + wet[i],pre[v] = i - 1;
        }
    }
}

void init()
{
    memset(head,0,sizeof head);
    memset(bridge,0,sizeof bridge);
    memset(indu,0,sizeof indu);
    memset(pre,0,sizeof pre);
    memset(ds,0,sizeof ds);
    memset(dt,0,sizeof dt);
    memset(sum,0,sizeof sum);
    memset(sum_b,0,sizeof sum_b);
    idx = 1;
    tot = 0;
}

void get_path(int x)
{
    if(x != S)get_path(edu[pre[x]]);
    ++tot;
    sum_b[tot] += sum_b[tot-1] + bridge[pre[x]] * edw[pre[x]];
    sum[tot] += sum[tot-1] + edw[pre[x]];
}

void dp()
{
    int k = 1;
    for(int i = 2;i <= tot;i ++)
    {
        while( sum[i] - sum[k] > q )k++;
        ds[i] = max(ds[i-1],sum_b[i] - sum_b[k] + (sum_b[k] - sum_b[k-1] > 0 ? q - (sum[i] - sum[k]) : 0 ) );
    }

    k = tot;

    for(int i = tot - 1;i >= 1;i --)
    {
        while( sum[k] - sum[i] > q )k--;
        dt[i] = max(dt[i+1],sum_b[k] - sum_b[i] + (sum_b[k+1] - sum_b[k] > 0 ? q - (sum[k] - sum[i]) : 0 ) );
    }
}

int main()
{
    int L;
    cin >> L;
    while(L --)
    {
        init();
        scanf("%d%d%d%d%d",&n,&m,&S,&T,&q);
        S++,T++;
        int xi,yi,zi;
        for(int i = 1;i <= m;i ++)
            scanf("%d%d%d",&xi,&yi,&zi),add(++yi,++xi,zi),indu[xi]++,edu[i] = xi,edv[i] = yi,edw[i] = zi;

        memset(cnt2,0,sizeof cnt2);
        bfs(T,cnt2);

        init();
        for(int i = 1;i <= m;i ++)
            add(edu[i],edv[i],edw[i]),indu[edv[i]]++;

        memset(cnt1,0,sizeof cnt1);
        bfs(S,cnt1);

        for(int i = 1;i <= m;i ++)
            bridge[i] = cnt1[edu[i]] * cnt2[edv[i]] % mod == cnt1[T] % mod;

        get_path(T);
        dp();

        LL ans = 0;
        for(int i = 1;i <= n;i ++)
            ans = max(ds[i]+dt[i],ans);

        cout << sum_b[tot] - ans << endl;
    }
}

C++ 解法, 执行用时: 483ms, 内存消耗: 11544K, 提交时间: 2022-04-10 19:38:40

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;
const int N = 1e5+5,M = 2*N,inf = 0x3f3f3f3f,mod = 1e9 + 7;

int tot,S,T,n,m,q,idx = 1,ver[M],wet[M],nxt[M],head[N],dis[N],indu[N],edu[M],edv[M],edw[M],pre[N];
queue<int> q1;
bool bridge[M];
LL dt[N],ds[N],cnt1[N],cnt2[N],sum_b[N],sum[N];
void add(int u,int v,int w){
    nxt[++idx] = head[u];
    ver[idx] = v;
    wet[idx] = w;
    head[u] = idx;
}
void bfs(int st,LL a[]){
    memset(dis,inf,sizeof dis);
    a[st] = 1;
    q1.push(st);
    dis[st] = 0;
    while(q1.size()){
        int u = q1.front();q1.pop();
        for(int i = head[u]; i ;i = nxt[i]){
            int v = ver[i];
            indu[v] --;
            if(!indu[v])q1.push(v);
            a[v] = (a[u] + a[v]) % mod;
            if(dis[v] > dis[u] + wet[i])
                dis[v] = dis[u] + wet[i],pre[v] = i - 1;
        }
    }
}
void init(){
    memset(head,0,sizeof head);
    memset(bridge,0,sizeof bridge);
    memset(indu,0,sizeof indu);
    memset(pre,0,sizeof pre);
    memset(ds,0,sizeof ds);
    memset(dt,0,sizeof dt);
    memset(sum,0,sizeof sum);
    memset(sum_b,0,sizeof sum_b);
    idx = 1;
    tot = 0;
}
void get_path(int x){
    if(x != S)get_path(edu[pre[x]]);
    ++tot;
    sum_b[tot] += sum_b[tot-1] + bridge[pre[x]] * edw[pre[x]];
    sum[tot] += sum[tot-1] + edw[pre[x]];
}
void dp(){
    int k = 1;
    for(int i = 2;i <= tot;i ++){
        while( sum[i] - sum[k] > q )k++;
        ds[i] = max(ds[i-1],sum_b[i] - sum_b[k] + (sum_b[k] - sum_b[k-1] > 0 ? q - (sum[i] - sum[k]) : 0 ) );
    }
    k = tot;
    for(int i = tot - 1;i >= 1;i --){
        while( sum[k] - sum[i] > q )k--;
        dt[i] = max(dt[i+1],sum_b[k] - sum_b[i] + (sum_b[k+1] - sum_b[k] > 0 ? q - (sum[k] - sum[i]) : 0 ) );
    }
}
int main(){
    int L;
    cin >> L;
    while(L --){
        init();
        scanf("%d%d%d%d%d",&n,&m,&S,&T,&q);
        S++,T++;
        int xi,yi,zi;
        for(int i = 1;i <= m;i ++)scanf("%d%d%d",&xi,&yi,&zi),add(++yi,++xi,zi),indu[xi]++,edu[i] = xi,edv[i] = yi,edw[i] = zi;
        memset(cnt2,0,sizeof cnt2);
        bfs(T,cnt2);
        init();
        for(int i = 1;i <= m;i ++)add(edu[i],edv[i],edw[i]),indu[edv[i]]++;
        memset(cnt1,0,sizeof cnt1);
        bfs(S,cnt1);
        for(int i = 1;i <= m;i ++)bridge[i] = cnt1[edu[i]] * cnt2[edv[i]] % mod == cnt1[T] % mod;
        get_path(T);
        dp();
        LL ans = 0;
        for(int i = 1;i <= n;i ++)ans = max(ds[i]+dt[i],ans);
        cout << sum_b[tot] - ans << endl;
    }
}

上一题