1. 程式人生 > 其它 >一個很好的在圖上的dp

一個很好的在圖上的dp

ABC244 E - King Bombee

題目連結
https://atcoder.jp/contests/abc244/tasks/abc244_e

解析
本題就是給了一個無向無環圖,然後問你從s到t經過k條路徑的方案數,要求經過的路徑中x只出現了偶數次.採用dp的做法.

  • 如果不考慮x出現偶數次,則dp方法與該題相同:
    https://atcoder.jp/contests/abc242/tasks/abc242_c
    用f[i][j]表示從起點到j經過i條邊的方案數.
  • 考慮x出現次數的奇偶,則應增加一維狀態表示(像是狀態壓縮dp)
    • f[i][j][0]表示從起點到j經過i條邊且有偶數個x的方案數
    • f[i][j][1]表示從起點到j經過i條邊且有奇數個x的方案數
  • 狀態轉移是通過圖中的邊來轉移的
  • 官方題解寫的很好,直接參考即可
    https://atcoder.jp/contests/abc244/editorial/3619

Ac程式碼

點選檢視程式碼
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
 
using namespace std;
 
typedef long long ll;
 
const int mod = 998244353;
const int N = 2010, M = 2 * N;
 
int h[N], e[M], ne[M], idx;
int n, m, k, s, t, x;
ll f[N][N][2];
 
void add(int a, int b){
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
}
 
int main()
{
    scanf("%d%d%d%d%d%d", &n, &m, &k, &s, &t, &x);
    memset(h, -1, sizeof h);
    while(m --){
        int a, b;
        scanf("%d%d", &a, &b);
        add(a, b), add(b, a);
    }
    f[0][s][0] = 1;
    for(int i = 1; i <= k; i ++){
        for(int j = 1; j <= n; j ++){
            for(int k = h[j]; k != -1; k = ne[k]){
                int tmp = e[k];
                if(tmp == x){
                    f[i][tmp][1] = (f[i][tmp][1] + f[i - 1][j][0]) % mod;
                    f[i][tmp][0] = (f[i][tmp][0] + f[i - 1][j][1]) % mod;
                }
                else{
                    f[i][tmp][1] = (f[i][tmp][1] + f[i - 1][j][1]) % mod;
                    f[i][tmp][0] = (f[i][tmp][0] + f[i - 1][j][0]) % mod;
                }
            }
        }
    }
    printf("%lld\n", f[k][t][0]);
 
    return 0;
}