【记忆化搜索+最短路】HDU 2833 WuKong

12 篇文章 0 订阅
10 篇文章 0 订阅
[url]http://acm.hdu.edu.cn/showproblem.php?pid=2833[/url]

[b][size=medium]题意:求2条最短路径的最多公共点数
首先要说的是:求出最短路后,如果dist[u] + map[u][v] = dist[v],则uv这条边必定在最短路上[/size][/b]


#include <iostream>
#include <fstream>
#include <algorithm>
#include <string>
#include <set>
//#include <map>
#include <queue>
#include <utility>
#include <iomanip>
#include <stack>
#include <list>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
//#include <ctime>
#include <ctype.h>
using namespace std;
#define LL __int64
#define inf 0x3fffffff
#define M 305

int n, map[M][M], d1[M], d2[M], dp[M][M];
bool mark[M];

void init ()
{
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
map[i][j] = inf;
memset (dp, -1, sizeof(dp));
}

void dijk (int u, int dist[])
{
memset (mark, false, sizeof(mark));
int mins, i, j, v;
for (i = 1; i <= n; i++)
dist[i] = map[u][i];
dist[u] = 0;
mark[u] = true;
while (1)
{
mins = inf;
for (j = 1; j <= n; j++)
if (!mark[j] && dist[j] < mins)
mins = dist[j], v = j;
if (mins == inf)
break;
mark[v] = true;
for (j = 1; j <= n; j++)
if (!mark[j] && dist[v] + map[v][j] < dist[j])
dist[j] = dist[v] + map[v][j];
}
}

int dfs (int a, int b)
{
if (dp[a][b] > -1) //记忆
return dp[a][b];
int i, j, v = 0; //v是重要的临时值
if (a == b) //a==b可以一起往前走一步
{
v++;
for (i = 1; i <= n; i++) //枚举第一条最短路的可以到达a的前一个点
{
if (d1[i] + map[i][a] != d1[a]) //ia不是最短路上的边
continue;
for (j = 1; j <= n; j++) //枚举第二条最短路的可以到达b的前一个点
if (d2[j] + map[j][b] == d2[b])
v = max (v, dfs (i, j)+1);
}
}
for (i = 1; i <= n; i++) //a往前走一步
if (d1[i] + map[i][a] == d1[a])
v = max (v, dfs (i, b));
for (i = 1; i <= n; i++) //b往前走一步
if (d2[i] + map[i][b] == d2[b])
v = max (v, dfs (a, i));
dp[a][b] = v;
return v;
}

int main()
{
int m, u, v, w, A, B, C, D;
while (scanf ("%d%d", &n, &m), (n||m))
{
init ();
while (m--)
{
scanf ("%d%d%d", &u, &v, &w);
if (w < map[u][v])
map[u][v] = map[v][u] = w;
}
scanf ("%d%d%d%d", &A, &B, &C, &D);
dp[A][C] = 0;
if (A == C) //dfs重要返回条件
dp[A][C] = 1;
dijk (A, d1);
dijk (C, d2);
printf ("%d\n", dfs (B, D)); //dfs(A, C)会超时……要从终点走回起点
}
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值