E - King Bombee(图上 dp)

11 篇文章 2 订阅

E - King Bombee


题意:

给出一个 n 个点,m 条边的简单无向图。
问,从 S 点到 T 点,共经过 K+1 个点,并且经过点 X 偶数次的路径条数。
2 ≤ N , M , K ≤ 2000 2≤N, M, K≤2000 2N,M,K2000
1 ≤ S , T , X ≤ N 1≤S,T,X≤N 1S,T,XN
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。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值