森林中的路 | ||||||
| ||||||
Description | ||||||
J老师的家在一片森林的一端,而他的工作地点则在另一端,最近他感到工作的压力很大,所以打算每天走路回家放松自己, | ||||||
Input | ||||||
输入包括多组数据,以一个0结束,J老师将所有的路口或者路从1开始标号,他的工作地点标为1,家标为2,每组数据第一 | ||||||
Output | ||||||
对于每组测试数据,输出一个整数表示穿过森林的不同路径总数,这个数量保证不会超过int的表示范围。 | ||||||
Sample Input | ||||||
5 6 | ||||||
Sample Output | ||||||
2 |
hdu题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1142
哈理工oj题目链接:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1347
hdu是英文版,理工oj上是翻译过来的版本,我们当然是直接看中文版本的比较开森辣~
思路:
1、首先明确一个点,题目中说明的能从a节点走到b节点的条件是b节点距离家比a节点距离家更近一些,才能从节点a走到节点b,那么不难想出,如果要比较a节点和家的距离以及b节点和家的距离谁近的问题,显然需要用到最短路算法来搞定这部分的处理,我们起点看似是节点1,其实做最短路的时候我们应该设起点为节点2,因为我们要求的是各个节点到2节点的距离,而非从节点1到其他各个节点的距离。
所以第一步,设节点2为源点做一遍最短路,得到节点2到其他各点的最短路,其实也就是求得了其他各点到节点2的最短距离。
2、对于路径数的统计,可以直接Dfs,设ans【n】然后走到一个点,对ans【】++,但是很可惜,这样做如果边多的话,层数深了的情况下,是会有很多很多很多很多操作,至于操作数会有多大?在杭电上output那块最后一句话有保证,You may assume that this number does not exceed 2147483647。那么最多情况的时候,会有2147483647这么多次深搜操作,可想而知是一定会超时的。
3、这个时候我们需要使用dp思想,设dp【2】=1,不难推出状态转移方程:dp【u】=sum(dp【v】)其中v是u所有能到达的子节点。最后输出dp【1】即可。其中有些逆向思维的感觉,大家参考代码仔细理解一下,并不是很难懂。
AC代码:
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;
int head[10000];
struct EdgeNode
{
int to;
int w;
int next;
}e[1000000];
int dp[10000];
int dis[10000];
int vis[10000];
int n,m,cont;
void add(int from,int to,int w)
{
e[cont].to=to;
e[cont].w=w;
e[cont].next=head[from];
head[from]=cont++;
}
void SPFA(int ss)
{
for(int i=1;i<=n;i++)dis[i]=0x3f3f3f3f;
queue<int >s;
s.push(ss);
dis[ss]=0;
vis[ss]=1;
while(!s.empty())
{
int u=s.front();
s.pop();vis[u]=0;
for(int k=head[u];k!=-1;k=e[k].next)
{
int v=e[k].to;
int w=e[k].w;
if(dis[v]>dis[u]+w)
{
dis[v]=dis[u]+w;
if(vis[v]==0)
{
s.push(v);
vis[v]=1;
}
}
}
}
}
void solve()
{
cont=0;
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
for(int i=0;i<m;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
add(x,y,w);
add(y,x,w);
}
SPFA(2);
}
int DP(int u)
{
if(dp[u]==0)
{
for(int k=head[u];k!=-1;k=e[k].next)
{
int v=e[k].to;
if(dis[v]<dis[u])
dp[u]+=DP(v);
}
return dp[u];
}
else return dp[u];
}
int main()
{
while(~scanf("%d",&n))
{
if(n==0)break;
scanf("%d",&m);
solve();
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
dp[2]=1;
DP(1);
printf("%d\n",dp[1]);
}
}