一种优化分层图建图方法

直接暴力建这样线特别乱得图 因为中转得关系 我们得暴力扫完这些中转
用一个虚拟点代表中专 这样建就 直接处理得换线得问题了

考虑分层图最短路。
很容易想到建 m 层图,如果多条地铁线都经过同一个点,则在这些点之间暴力两两连边,这样连边是 O(nm^2)的,可能会超时。
我们可以多建一层虚点,所有点到它对应的虚点不需要代价,从虚点到它对应的点需要对应的代价,这样就可以优化到 O(nm) 建图。最后跑一边最短路就好了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> P;
const int maxn = 1e3 + 5;
 
int n, m, s, t;
int head[500 * maxn], cnt;
int to[maxn * 1000], nxt[maxn * 1000], val[maxn * 1000];
 
void ade(int a, int b, int c) {
    to[++ cnt] = b, val[cnt] = c;
    nxt[cnt] = head[a], head[a] = cnt;
}
 
bool vis[maxn * 500];
int dis[maxn * 500];
void dijkstra(){
    priority_queue<P> que;
    que.push(P(0, s));
    memset(dis, 0x3f, sizeof dis);
    dis[s] = 0;
    while(!que.empty()) {
        P p = que.top(); que.pop();
        int u = p.second;
        if(u == t) {
            cout << -p.first << endl;
            return ;
        }
        if(vis[u]) continue;
        vis[u] = 1;
        for(int i = head[u]; i; i = nxt[i]) {
            int v = to[i];
            if(dis[v] > dis[u] + val[i]) {
                dis[v] = dis[u] + val[i];
                que.push(P(-dis[v], v));
            }
        }
    }
    cout << -1 << endl;
}
 
int main(){
    cin >> n >> m >> s >> t;
    for(int i = 1, a, b, c; i <= m; i ++) {
        cin >> a >> b >> c;
        for(int j = 1, u, v; j <= c; j ++) {
            cin >> v;
            if(j > 1)
                ade((i - 1) * n + u, (i - 1) * n + v, b), \
                ade((i - 1) * n + v, (i - 1) * n + u, b);
             
            ade((i - 1) * n + v, m * n + v, 0), \
            ade(m * n + v, (i - 1) * n + v, a);
            u = v;
        }
    }
    t = n * m + t;
    s = n * m + s;
    dijkstra();
    return 0;
}

牛客 多校 6场 D题 move

选择 K个变费用0 这个图建立起 没有什么边得互相限制
只有处理K
所以就不像上面呢样难了 只有K层图 每次图都一样 限制得K 只改变这次路得费用

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e3 + 10;
int cas, n, m;
int a[maxn];

bool chk(int mid) {
    bool vis[maxn] = {0};
    int res = 0, v = 0;
    for(int i = 1; i <= m; i ++) {
        v = 0;
        for(int j = n; j >= 1; j --) {
            if(mid - v >= a[j] && !vis[j]) {
                vis[j] = 1;
                v += a[j];
                res ++;
            }
        }
    }
    if(res != n) return 1;
    else return 0;
}

int main() {
	scanf("%d", &cas);
	for(int kk = 1; kk <= cas; kk ++) {
        scanf("%d %d", &n, &m);
        int sum = 0;
        for(int i = 1; i <= n; i++) {
            scanf("%d", a + i);
            sum += a[i];
        }
        sort(a + 1, a + 1 + n);
        int l = sum / m, r = a[n] + sum / m;
        while(chk(l)) l ++;
        printf("Case #%d: %d\n", kk, l);
	}
    return 0;
}