您的位置:首页 > 其它

zoj 3644(dp + 记忆化搜索)

2014-03-18 22:12 302 查看
题目链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4834

思路:dp[i][j]表示当前节点在i,分数为j的路径条数,从题中可以得出,要在N处的分数为K,那么那些到达N的路径上的节点的val必然是K的因子,由于K的范围为[1, 1000000],二维数组开不下,那么我们可以用一个数组来保留K的所有因子,在用一个数组来保留这个因子的值,这样,二维数组就可开了,于是,就是记忆化搜索了!

/*************************************************************************
> File Name: zoj3644.cpp
> Author: syhjh
> Created Time: 2014年03月18日 星期二 20时47分15秒
************************************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

const int MAXN = (2000 + 20);
const int MAXM = (200000 + 200);
const int MAX = (1000000 + 100);
const int MOD = (1000000007);
template < class T > inline T GCD(T a, T b)
{
return b == 0 ? a : GCD(b, a % b);
}

template < class T > inline T LCM(T a, T b)
{
return a / GCD(a, b) * b;
}

struct Edge {
int v, next;
} edge[MAXM];

int N, M, K, val[MAXN];
int NE, head[MAXN];

void Insert(int u, int v)
{
edge[NE].v = v;
edge[NE].next = head[u];
head[u] = NE++;
}

int dp[MAXN][MAXN];
int pp[MAX], num[MAXN];

void Init()
{
memset(pp, -1, sizeof(pp));
int cnt = 0;
for (int i = 1; i <= K; i++) {
if (K % i == 0) {
pp[i] = cnt;
num[cnt++] = i;
}
}
}

int getDp(int u, int s)
{
if (s == -1) return 0;
if (u == N && num[s] == K) {
return 1;
}
if (dp[u][s] != - 1) return dp[u][s];
int ans = 0;
for (int i = head[u]; i != -1; i = edge[i].next) {
int v = edge[i].v;
if (K % val[v]) continue;
int tmp = LCM(num[s], val[v]);
if (tmp != num[s] && K % tmp == 0) {
ans += getDp(v, pp[tmp]);
ans %= MOD;
}
}
return dp[u][s] = ans;
}

int main()
{
while (cin >> N >> M >> K) {
NE = 0;
memset(head, -1, sizeof(head));
while (M--) {
int u, v;
cin >> u >> v;
Insert(u, v);
}
for (int i = 1; i <= N; i++) {
cin >> val[i];
}
Init();
memset(dp, -1, sizeof(dp));
cout << getDp(1, pp[val[1]]) << endl;
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: