E - King Bombee
题意:
给出一个 n 个点,m 条边的简单无向图。
问,从 S 点到 T 点,共经过 K+1 个点,并且经过点 X 偶数次的路径条数。
2
≤
N
,
M
,
K
≤
2000
2≤N, M, K≤2000
2≤N,M,K≤2000
1
≤
S
,
T
,
X
≤
N
1≤S,T,X≤N
1≤S,T,X≤N
X
≠
S
,
X
≠
T
X≠S, X≠T
X=S,X=T
分析:
求方案数,加上复杂度许可,要能想到用dp。
定义:
f[i, j, k]
:从起点走 i
步,到达点 j
时经过点 x
的奇偶性为 k
的方案数。
初始化:f[0, s, 0] = 1
;
那么,首先遍历走的步数 i,再遍历到达的点 j:
- 如果当前点 j 是 x,那么
f[i, j, 0]
从其相邻点,走i-1步,经过点 x 奇数次的状态转移:f[i, j, 0] += f[i-1, tx, 1];
f[i, j, 1]
从其相邻点,走i-1步,经过点 x 偶数次的状态转移:f[i, j, 0] += f[i-1, tx, 0];
- 当前点不是 x,则
f[i, j, 0]
从其相邻点,走i-1步,经过点 x 偶数次的状态转移:f[i, j, 0] += f[i-1, tx, 0];
f[i, j, 1]
从其相邻点,走i-1步,经过点 x 奇数次的状态转移:f[i, j, 1] += f[i-1, tx, 1];
f[0][s][0] = 1;
for(int i=1;i<=k;i++)
{
for(int j=1;j<=n;j++)
{
for(auto tx:e[j])
{
if(j!=x){
f[i][j][0] = (f[i][j][0] + f[i-1][tx][0])%mod;
f[i][j][1] = (f[i][j][1] + f[i-1][tx][1])%mod;
}
else{
f[i][j][0] = (f[i][j][0] + f[i-1][tx][1])%mod;
f[i][j][1] = (f[i][j][1] + f[i-1][tx][0])%mod;
}
}
}
}
cout << f[k][t][0];
完整Code:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2010, mod = 998244353;
int T, n, m, k;
int a[N];
vector<int> e[N];
int f[N][N][2];
signed main(){
Ios;
int s, t, x;
cin>>n>>m>>k>>s>>t>>x;
while(m--)
{
int x,y;cin>>x>>y;
e[x].pb(y);
e[y].pb(x);
}
f[0][s][0] = 1;
for(int i=1;i<=k;i++)
{
for(int j=1;j<=n;j++)
{
for(auto tx:e[j])
{
if(j!=x){
f[i][j][0] = (f[i][j][0] + f[i-1][tx][0])%mod;
f[i][j][1] = (f[i][j][1] + f[i-1][tx][1])%mod;
}
else{
f[i][j][0] = (f[i][j][0] + f[i-1][tx][1])%mod;
f[i][j][1] = (f[i][j][1] + f[i-1][tx][0])%mod;
}
}
}
}
cout << f[k][t][0];
return 0;
}
补完这道题之后,发现第一维的状态都是从前面更新过来,那么就很像01背包的二维状态压成一维的条件,所以就想到,如果说这道题的图是有向无环图,空间复杂度再小些,就可以用反向拓扑序来转移状态,把第一维压掉。
仔细想想,确实可行哎。
那是不是就可以这样再出一道题了?嘻嘻。(或者是我想错了。。
但是这道题在图上用dp确实没想到,以后要多练dp。