本文共 6697 字,大约阅读时间需要 22 分钟。
先对图进行预处理,再进行DP。一般都有两种套路,拓扑序或如Dijkstra或SPFA的最短路算法。
思路:在1->2的任意路径上有环即为inf。但是环若是在死路上就没影响。所以先在正向图从1开始DFS所有点,并标记1。在反向图从2开始DFS所有点,并标记为2。最后,被1和2都标记过的点即为路径上的点。其他点不参与后面运算。
后面直接按拓扑序DP即可,若最后2的入度不为0,说明路径上有环,inf。否则输出dp[2].#include#define endl '\n'#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);using namespace std;const int N = 1e5 +5, mod = 1e9;const double eps = 1e-10;using LL = long long;int n, m;vector G[N], NG[N];int vis[N], nvis[N], f[N], in[N];void dfs(vector Path[], int flag[], int u){ flag[u] = 1; for(int v : Path[u]){ if(!flag[v]){ dfs(Path, flag, v); } }}void topoSort(){ for(int i = 1; i <= n; ++i){ if(!vis[i])continue; for(int u : G[i]){ if(!vis[u])continue; ++in[u]; } } queue Q; for(int i = 1; i <= n; ++i){ nvis[i] = 0; if(vis[i] && !in[i]) Q.push(i); } f[1] = 1; while(!Q.empty()){ int u = Q.front(); Q.pop(); if(u == 2)return; for(int v : G[u]){ if(!vis[v])continue; f[v] = (f[v] + f[u]) % mod; if(--in[v] == 0)Q.push(v); } } cout << "inf" << endl; exit(0);}int main(){ IOS; cin >> n >> m; for(int x, y, i = 1; i <= m; ++i){ cin >> x >> y; G[x].push_back(y); NG[y].push_back(x); } dfs(G, vis, 1); dfs(NG, nvis, 2); for(int i = 1; i <= n; ++i){ //cout << i << ": " << vis[i] << " " << nvis[i] << endl; vis[i] = vis[i] + nvis[i] == 2 ? 1 : 0; } if(!vis[2]){ cout << 0 << endl; exit(0); } topoSort(); cout << f[2] << endl;}
普通的图上面DP,由于有环的存在,一部分DP具有后效性,故需要用最短路算法(Dijkstra或SPFA)来解决。另一部分DP,则有可能是图上DFS,记忆化搜索。
做法:通过Floyd得到 d [ i ] [ j ] d[i][j] d[i][j]。初始化 f [ 1 ] [ 1 ] = 1 f[1][1]=1 f[1][1]=1,由于DP的后效性,使用SPFA进行DP,每次DP都更新 f [ 1 ⋯ n ] [ 1 ⋯ n ] f[1\cdots n][1\cdots n] f[1⋯n][1⋯n]所有的点(不包括f[x][y]),直到所有f都无法更新。最后答案就是 f [ 2 ] [ 2 ] f[2][2] f[2][2]
#include#define endl '\n'#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);using namespace std;const int N = 1e3 +5, mod = 1e9;int n, m;vector G[N];int d[N][N], f[N][N], in[N][N];struct Node{ int x, y; Node(int x = 0, int y = 0):x(x), y(y) { }};int main(){ IOS; int n, m; cin >> n >> m; memset(d, 0x0f, sizeof(d)); for(int x, y, i = 1; i <= m; ++i){ cin >> x >> y; G[x].push_back(y); d[x][y] = 1; } for(int i = 1; i <= n; ++i) d[i][i] = 0; for(int k = 1; k <= n; ++k) for(int i = 1; i <= n; ++i) for(int j = 1; j <= n; ++j) d[i][j] = min(d[i][j], d[i][k] + d[k][j]); memset(f, 0x7f, sizeof(f)); queue pq; f[1][1] = 1; pq.emplace(1, 1); in[1][1] = 1; while(!pq.empty()){ int x = pq.front().x, y = pq.front().y; in[x][y] = 0; pq.pop(); for(int a = 1; a <= n; ++a){ for(int b = 1; b <= n; ++b){ if(a==x && b==y)continue; if(f[a][b] > f[x][y] + d[y][a] + d[a][b] + d[b][x] - 1){ f[a][b] = f[x][y] + d[y][a] + d[a][b] + d[b][x] - 1; if(in[a][b])continue; in[a][b] = 1; pq.emplace(a, b); } } } } cout << f[2][2] << endl;}
#include#define endl '\n'#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);using namespace std;typedef long long LL;const int N = 1e5 +5, mod = 1e9;vector > G[N], NG[N];LL dis[N], f[N][55];int in[N];LL n, m, k, p, flag;void spfa(int s, int t){ memset(dis, 0x0f, sizeof(dis)); dis[s] = 0; queue Q; Q.push(s); while(!Q.empty()){ int u = Q.front(); in[u] = 0; Q.pop(); for(auto it : G[u]){ int c = it.second, v = it.first; if(dis[u] + c < dis[v]){ dis[v] = dis[u] + c; if(in[v])continue; in[v] = 1; Q.emplace(v); } } }}int dfs(int u, int ex){ if(~f[u][ex])return f[u][ex]; f[u][ex] = -2; LL ans = u == 1 && ex == 0; for(auto it : NG[u]){ int c = it.second, v = it.first; if(dis[u] + ex - dis[v] - c < 0)continue; if(f[v][dis[u] + ex - dis[v] - c] == -2){ flag = 0; return 0; } ans += dfs(v, dis[u] + ex - dis[v] - c); ans %= p; } return f[u][ex] = ans;}int main(){ IOS; int T; cin >> T; while(T--){ cin >> n >> m >> k >> p; for(int i = 1; i <= n; ++i){ G[i].clear(); NG[i].clear(); } for(int i = 1, x, y, z; i <= m; ++i){ cin >> x >> y >> z; G[x].emplace_back(y, z); NG[y].emplace_back(x, z); } spfa(1, n); LL ans = 0; memset(f, -1, sizeof(f)); flag = 1; for(int i = 0; i <= k && flag; ++i){ ans += dfs(n, i); ans %= p; } cout << (flag ? ans : -1) << endl; }}
转载地址:http://cwuzi.baihongyu.com/