首页 > 其他分享 >CF238E Meeting Her【DP,最短路】

CF238E Meeting Her【DP,最短路】

时间:2022-09-25 20:46:29浏览次数:72  
标签:必经 ch int MN read CF238E Meeting DP define

传送门


显然,如果节点 \(u\) 不是 \(s_i \to t_i\) 的必经点,那么在 \(u\) 等 \(i\) 号车是没有前途的。类似地,若在 \(u\) 处上了 \(i\) 号车,且 \(v\) 不是 \(s_i \to t_i\) 的必经点,那么也不可能从 \(u\) 直接到 \(v\)。

那么一个简单的想法是直接把每条边对应的必经点连边跑最短路,当然这样是错的,考虑下面这种情况:\(s_i \to t_i\) 上的某两个点可能都不是路径 \(i\) 的必经点,但是它们分别是路径 \(j,k\) 的必经点,而 \(j,k\) 同时能够到达 \(b\),那么 \(i\) 其实一定能够到达 \(b\),于是就寄了。

上述做法的问题在于,当我们在坐上 \(i\) 号车后就铁了心要在路径 \(i\) 的必经点上换乘,然而实际情况可能并不是这样。

我们不妨把所有 \(O(nk)\) 种状态都表示出来,设 \(f_{i,j}\) 为在点 \(i\) 坐 \(j\) 号车的最少换乘次数,\(S_{i \to j}\) 表示 \(i \to j\) 最短路上的点集,\(T_i\) 表示路径 \(i\) 的必经点集,考虑换乘还是继续坐,有转移:

\[f_{i,j} = \min\left( \max_{p \in S_{i \ \to \ t_j}} f_{p,j}, \ 1 + \min_{i \in T_k} f_{i,k}\right) \]

初始值 \(f_{b,i} = 0(b \in S_{s_i \to t_i})\),答案即为 \(\min \{ f_{a,i} \}(a \in T_i)\)。

那个 \(\max\) 是因为公交车一定会走最坏的路线。由于转移只有在换乘的时候才会加 \(1\),因此 \(f\) 的值域是 \(O(n)\) 的。于是可以类似 dijkstra 分层转移,每次把 \(f\) 值为 \(i\) 的状态拿出来更新其他状态。

第二种转移可以直接做,第一种转移我们对 \(S_{s_i \ \to \ t_i}\) 建反图,显然这是个 DAG,可以用类似拓扑排序的方式转移。由于要取 \(\max\),而我们刚好是从小到大枚举权值,用最后一个后继来更新即可。

注意转移顺序:由于在第一种转移中可能会把前驱的 \(f\) 值也变成 \(i\),因此先进行第一种转移,然后枚举所有 \(f\) 值为 \(i\) 的状态进行第二种转移。

预处理 \(T_i\) 和 \(S_{i \to j}\) 即可做到 \(O(n^4 + n^2k)\),精细实现预处理可以做到 \(O(n^3+n^2k)\),代码偷懒写了 \(n^4\) 的。

code
/*
最黯淡的一个 梦最为炽热
万千孤单焰火 让这虚构灵魂鲜活
至少在这一刻 热爱不问为何
存在为将心声响彻
*/
#include <bits/stdc++.h>
#define pii pair<int, int>
#define mp(x, y) make_pair(x, y)
#define pb push_back
#define eb emplace_back
#define fi first
#define se second
#define int long long
#define mem(x, v) memset(x, v, sizeof(x))
#define mcpy(x, y) memcpy(x, y, sizeof(y))
#define lob lower_bound
#define upb upper_bound
#define all(x) (x).begin(), (x).end()
#define TIME 1e3 * clock() / CLOCKS_PER_SEC
using namespace std;

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

const int MN = 1e2 + 5;
const int Mod = 998244353;
const int inf = 1e18;

inline int min(int x, int y) { return x < y ? x : y; }
inline int max(int x, int y) { return x > y ? x : y; }

inline int qPow(int a, int b = Mod - 2, int ret = 1) {
    while (b) {
        if (b & 1) ret = ret * a % Mod;
        a = a * a % Mod, b >>= 1;
    }
    return ret;
}

#define dbg

int N, M, K, a, b, s[MN], t[MN];
int dis[MN][MN], f[MN][MN], g[MN][MN], _dis[MN][MN], d[MN][MN], on[MN][MN], mst[MN][MN];
vector <int> e[MN][MN];

signed main(void) {
    N = read(), M = read(), a = read(), b = read();
    mem(dis, 0x3f);
    for (int i = 1; i <= N; i++) dis[i][i] = 0;
    for (int i = 1; i <= M; i++) {
        int x = read(), y = read();
        dis[x][y] = 1;
    }
    K = read();
    for (int i = 1; i <= K; i++) s[i] = read(), t[i] = read();
    mcpy(g, dis);
    for (int k = 1; k <= N; k++)
        for (int i = 1; i <= N; i++)
            for (int j = 1; j <= N; j++) 
                dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
    for (int u = 1; u <= N; u++) {
        mcpy(_dis, g);
        for (int i = 1; i <= N; i++) 
            _dis[i][u] = _dis[u][i] = inf;

        for (int k = 1; k <= N; k++)
            for (int i = 1; i <= N; i++)
                for (int j = 1; j <= N; j++)
                    _dis[i][j] = min(_dis[i][j], _dis[i][k] + _dis[k][j]);

        for (int i = 1; i <= K; i++)
            mst[u][i] = _dis[s[i]][t[i]] != dis[s[i]][t[i]];
    }
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= K; j++)
            on[i][j] = dis[s[j]][t[j]] == dis[s[j]][i] + dis[i][t[j]];
    mem(f, 0x3f);
    for (int i = 1; i <= K; i++)
        if (on[b][i]) f[b][i] = 0;
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= K; j++)
            for (int k = 1; k <= N; k++)
                if (on[i][j] && on[k][j] && dis[i][t[j]] + 1 == dis[k][t[j]] && dis[k][i] == 1) d[k][j]++, e[i][j].pb(k);

    for (int i = 0; i < N; i++) {
        queue <pii> q;
        for (int j = 1; j <= N; j++)
            for (int k = 1; k <= K; k++) 
                if (f[j][k] == i) q.push(mp(j, k)); 
        while (!q.empty()) {
            pii x = q.front(); 
            q.pop();
            for (int j : e[x.fi][x.se])
                if ((!--d[j][x.se]) && f[j][x.se] > i) f[j][x.se] = i, q.push(mp(j, x.se));
        }
        for (int j = 1; j <= N; j++)
            for (int k = 1; k <= K; k++)
                if (f[j][k] == i && mst[j][k])
                    for (int p = 1; p <= K; p++)
                        f[j][p] = min(f[j][p], f[j][k] + 1);
    }
    int ans = inf;
    for (int i = 1; i <= K; i++) if (mst[a][i]) ans = min(ans, f[a][i]);
    printf("%lld\n", ans < inf ? ans + 1 : -1);
    return 0;   
}

标签:必经,ch,int,MN,read,CF238E,Meeting,DP,define
From: https://www.cnblogs.com/came11ia/p/16728715.html

相关文章

  • 【源码笔记】ThreadPoolExecutor#runWorker
    /***Mainworkerrunloop.Repeatedlygetstasksfromqueueand*executesthem,whilecopingwithanumberofissues:**1.Wemaystartoutwithanin......
  • WPF获取系统dpi
    WPF获取系统dpivardpiX=(int)typeof(SystemParameters).GetProperty("DpiX",BindingFlags.NonPublic|BindingFlags.Static).GetValue(null,null);vardpiY=(int......
  • AdPlus——尺寸单位
    尺寸单位CAD图纸/界面中单位是毫米mm程序中单位是厘米cm使用时://比例除以10#ifndefSYSTEMPROPORTION#definesystemProportion10#endifpile->setPileHigh(leng......
  • Upper-Intermediate10-01-Opening a Meetings
    1VocabularyMeetingsDialogueJOAN:Okay,Let'sgetstarted.Doyouallhavetheagenda?JOAN:Thepurposeofthismeetingistotalkaboutourrelationshipwith......
  • 关于区间DP的一点点心得(虽然还是很菜)
    关于区间DP的一点点心得区间DP的数组一般是二维,其状态一般表示区间\((l,r)\)。区间DP在思考的时候是有一定套路的,思考时可以按照如下方式进行思考:这段区间要......
  • dpdk21.11 添加igb_uio模块
    目录IGB_UIO模块两种添加方式零、下载IGB_UIO模块一、直接添加到文件中1.1复制dpdk-kmods/linux/igb_uio/到dpdk-stable-21.11.1/kernel/linux/目录下1.2修改mes......
  • expdp 排除特定表以及query导出部分数据
    在dba日常运维过程经常会用到导出某个schema并排除部分表,或者是某个表里的部分数据这种需求。1.导出schema排除特定表(通过sys导出)特殊字符需要转义,否则会报错expdp\'sy......
  • dp套路
    开始补dp了。状压dp常见套路:数据范围小,能将状态用\(0/1\)表示,且状态的表示一般有所限制(例如不能将两个\(1\)放在一起)。若设当前行状态为\(S\),则\((S<<1)\&S\)......
  • wxWidgets UI 库 简单示例和 高清屏 DPI 适配
    wxWidgets是一种跨平台开发的UI库,winmacOSubuntu都有很好的本地实现。版权友好,个人商业用途都可以,静态编译也比较容易,开发的比较出名的软件有:Filezilla、Aegisub......
  • 数位DP
    模板题:1082.数字游戏题目描述求整数区间[L,R][L,R]内,不降数的个数不降数:数位从高到低呈非下降关系(【例】:123,446)代码#include<bits/stdc++.h>usingnamespace......