HDU 2833 WuKong

【记忆化搜索+图论】HDU-2833-WuKong 具体题解 题目 #include using namespace std; template T Max(T x,T y){return x>y?x:y;} template T Min(T x,T y){return x<y?x:y;} #define N 305 #define inf 999999999 int n,dis1[N],dis2[N],dp[N][N],map[N][N] 阅读详情

传送门

求两条最短路最多重叠的点数。
给一个无向图,再给两对起点终点,每一对起点终点之间都可能有多条最短的路,设s1t1的最短路是r1s2t2的最短路是r2,求r1r2最多能相互重叠多少个点。

这道题思想很巧妙,涉及了dp的思想。首先想明白一个问题,两条最短路最多的重叠部分必然是连续的,不可能有两段或更多段分散的重叠部分。为什么?反证法,若有的话,则某两段重叠部分之间的各自的分散部分一定可以都采用更小的那段分散部分。

建立一个数组cnt[][]记录全图的两点之间的最短路最多可以有多少条边,使用floyd算法,在g[i][k]+g[k][j] < g[i][j]g[i][k]+g[k][j] == g[i][j]两种情况下对cnt[i][j]进行计算。然而,还要对cnt[][]数组进行初始化,很直接的想法就是初始边的两点设为1,没有边的两点为0。但是,这里有一个坑!输入数据中实锤有自环! 自环意味着cnt[x][x]也被设为了1,但是这是不符合定义的,除非你这个自环的权值是非正数,但是根据题意,权值的实际意义是路的长度,都是正值。(如果是非正的话这题也就GG了,有可达的零环意味着可以在这个零环上走到死,使得重叠的点数无穷大,有可达的负环意味着你连最短路都求不出来)
说这么多就很简单,当a,b两点之间有边时,要在cnt[a][b] = cnt[b][a] = 1之前加上条件a != b

接下来提一下上述情况具体运行到哪里出了问题。
答案:当k==i或者k==j时,在floyd里的cnt[i][j] < cnt[i][k] + cnt[k][j]这个条件下引发了错误判断,继而计算了错误值。(想一想我在这个里面提过的三个情况)
证据:把输入边时的a!=b条件去掉,在floyd的此处加上条件&&(k!=i)&&(k!=j),也AC了。

最后,枚举每两个点,判断这两点之间的最短路能不能同时成为s1,t1s2,t2的最短路的一部分,这个判断的写法很巧妙,和cnt[][]没关系。若可以的话我们再拿这两点cnt[][]的值更新ans。(虽然这两点之间可能有多条最短路,但是这些最短路都是首尾一致的,可以随意替换,于是我们都拿cnt[][]最大的那个当作子路)

(4月9日更新:其实这个题只要在floyd里面让i,j,k各不相等就行了)


#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <string>
#include <queue>
using namespace std;

const int INF = 1e9;
const int MAXN = 301;
int N, M;

int g[MAXN][MAXN];
int cnt[MAXN][MAXN];          // 两点的所有最短路上最多有几条边
int ans;

void init()
{
	for (int i = 1; i <= N; i++)
	{
		for (int j = i; j <= N; j++)
		{
			if (i == j) g[i][j] = 0;
			else g[i][j] = g[j][i] = INF;
		}
	}
	memset(cnt, 0, sizeof cnt);
	ans = -1;
}

int main()
{
	int a, b, c, d;
	for (; ~scanf("%d%d", &N, &M);)
	{
		if (!N && !M) break;
		init();
		for (int i = 0; i < M; i++)
		{
			scanf("%d%d%d", &a, &b, &c);
			g[a][b] = g[b][a] = min(g[a][b], c);
			if (a != b)                            // 如果来 X X Y 的数据怎么办? (自环)(Y肯定大于0)
				cnt[a][b] = cnt[b][a] = 1;         // 必须始终让cnt[x][x]=0,无论有没有自环,因为永远都不能走这个自环!                                      
		}
		scanf("%d%d%d%d", &a, &b, &c, &d);

		for (int k = 1; k <= N; k++)
		{
			for (int i = 1; i <= N; i++)
			{
				for (int j = 1; j <= N; j++)
				{
					if (g[i][k] != INF && g[k][j] != INF && g[i][k] + g[k][j] < g[i][j])
					{
						g[i][j] = g[i][k] + g[k][j];
						cnt[i][j] = cnt[i][k] + cnt[k][j];
					}
					else if (g[i][k] + g[k][j] == g[i][j] && cnt[i][j] < cnt[i][k] + cnt[k][j])
					{
						cnt[i][j] = cnt[i][k] + cnt[k][j];
					}
				}
			}
		}
		for (int i = 1; i <= N; i++)
		{
			for (int j = 1; j <= N; j++)
			{
				if (cnt[i][j] > ans)
				{
					if (g[a][b] == g[a][i] + g[i][j] + g[j][b] && g[c][d] == g[c][i] + g[i][j] + g[j][d])
					{                               // 表示i,j的最短路至少可以是a,b其中一条最短路的子路
						ans = cnt[i][j];
					}
				}
			}
		}
		printf("%d\n", ans + 1);     // 可以证明两条最短路的重叠部分一定是连续的,所以再加1等于重叠的点数
	}

	return 0;
}
HDU2833 WuKong(floyd + dp)经典 WuKong Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1429    Accepted Submission(s): 517 Problem Description Liyuan wanted to rewrite 阅读详情

相关推荐

HDU2833 WuKong floyd+DP

传送门:【HDU2833 WuKong ti m

poursoul 809

HDU 2833 大流判满流

题意:n个人 #include #include #include #include #define INF 0x7fffffff #define M 550000 #define N 1005 using namespace std; int head[N],cnt,nv; struct edge{ int v,next,cap,flow; }e[M]; void i

AB 720

hdu2833(2009多校第一场) 两条多交点

用floyd处理短路的同时更新路上多节点。 然后枚举重合线段,只要符合两条都是短路即可更新ans。 1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 using namespace std; 5 int dis[315][315],num[315]...

weixin_33801856的博客 154

HDU 2833 WuKong(floyd短路

题目地址:HDU 2833 这题想到了后是通过dis[s][t]==dis[s][i]+dis[i][j]+dis[j][t]的思路来判定是否属于短路的一条。。但是没想到可以用floyd来找短路中的点数。。。短路还是太渣了。。好多性质都不会利用。。 这题的思路就是通过floyd对每两个点之间的短路条数进行计数,然后通过上面的公式(对两条路线均要判定,都符合才说明都可以走),再找短路

scf0920 1306

HDU 2833 WuKong 短路

WuKong Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 208 Accepted Submission(s): 88   Problem Description Liyua

窦小雨的小点子 351

hdu2833 WuKong

给定两个起点终点,求两条短路径上的交集点数。 求了短路之后,枚举两条路上每条必然属于短路径上的路径,(d[u]+w==d[v],则该条路径必然在短路径上) dp[a][b]表示以a b为终点的交集点数。 #include #include #include #include #include #include #include #includ

Unknown 866

hdu 2833 WuKong【floyd】

题目连接:http://acm.hdu.edu.cn/showproblem.php?pid=2833 题意:悟空有一个起点终点,唐僧有一个起点终点,求他俩短路径上多 的交点个数。 分析:首先要知道它们的多交点一定是一段连续的路径,因为如果不是连续的 则说明存在其他短路段,都短而多交点不连续矛盾,我表达力不强不信就 试试。 然后可以用floyd跑全图的短路,并且记录任意两

letterwuyu的专栏 762

hdu 2833 WuKong

Dijkstra+记忆化搜索 首先用Dijkstra分别找到悟空和唐僧从起到终点的短路短路径的性质d[i] + edge[i][j] == d[j] 其中j为短路径上的点,则i也为短路径上的点。 由这个性质我们可以从终点逆向找到所有的短路径上的点,做一遍记忆化搜索就可以得到结果。 #include #include #include using nam

tju_virus的专栏 559

HDU2833 WuKong Floyd

/* Floyd的应用 用Floyd求出任意两点间的短路径 两个定理: 1.所求的路径一定是一断连续的路径 2.如果路径(x,y)是a->b的短路径中的一段,则min(a,b) = min(a,x) + min(x,y) + min(y,b) 后只需找到同时在两条短路径上,且距离最长的那一段 */ #include using namespace std; const int inf=

幸福在路上 1404

WuKong-HDU2833

题目:http://acm.hdu.edu.cn/showproblem.php?pid=2833 题意:给定无向图,求两条短路A->B,C->D,问这两条短路的公共点多有多少个 思路:1:floyd预处理所有点对短路:           2:记忆化搜索: 首先A->B的短路径,可以形成一棵有根树, 沿着A->B的短路径形成的树,从A开始搜索, dp[u],表示从u->B

wen_xp的专栏 470

HDU 2833——wukong

dijskra算法+搜索 首先分别求出悟空和唐僧各自的短路径,然后记忆化搜索。 #include #include #include using namespace std; #define maxn 302 #define INF 10001 int map[maxn][maxn],dis1[maxn],dis2[maxn]; int dp[maxn][maxn]; void dij1(i

1119

DP WuKong hdu2833

挺好的一道题 想到对于任意两点(可相同),如果两路径都经过那么一定是走同样的两点之间的短路 这道题就迎刃而解啦 代码如下: /* ^^ ====== ^^ ID: meixiuxiu PROG: test LANG: C++11 */ #include #include #include #include #include #include #include #incl

meixiuxiudd的博客 362

HDU-2833-WuKong

ACM模版描述题解很有趣的一道题……给定一个无向图,和两对起点终点,求两条短路上的多公共交点数。 可以dp+Floyd(代码One)搞搞,也可以dij+dfs(代码Two)搞搞,记忆化搜索,其实说白了都是dp。代码One:#include <iostream> #include <cstdio> #include <cstring> #include <algorithm>using name

逐梦者 569

HDU 2833 WuKong(floyd+dp)

题意:给你一张图,以及2对点,要求这2对点的短路多能有多少点是共有的。 在做floyd的时候加上一个数组num来代表从i到j短路多能有几个点。 然后枚举i,j,如果i到j是起点a到终点b的短路上的,那么dis[a][b] = dis[a][i]+dis[i][j]+dis[j][b],或者 dis[a][b] = dis[b][i]+dis[i][j]+dis[j][a] 然后这

glq007的acm的奋斗 548
上一篇: HDU 2377 Bus Pass
下一篇: HDU 1688 Sightseeing
Crossing over
博客等级 码龄10年 6粉丝 113原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值