本文主要是介绍poj 3411 Paid Roads,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
这题很特别,因为标记不能简单的为一次,他有可能为多次。。
但又不能不标记,不然无法结束。。
大致题意:
有n座城市和m(1<=n,m<=10)条路。现在要从城市1到城市n。有些路是要收费的,从a城市到b城市,如果之前到过c城市,那么只要付P的钱,如果没有去过就付R的钱。求的是最少要花多少钱。
注意:路径是有向的。
这题难点在于“城市与城市之间可能存在多条路径”:
1、 输入数据时可能会出现多条 从城市a到城市b的路径信息,但是费用有所差别;
2、 对于 从城市a到城市b 的同一条路径,允许重复走。
先来看一组数据:
6 5
1 2 1 10 10
2 3 4 10 100
2 4 2 15 15
4 1 1 12 12
3 6 6 10 10
如果每条路只允许走一次,那么方案只有1个:
1à2à3à6 共135元
但这组数据的正确答案是67元。为什么?正确的方案如下:
1à2à4à1à2à3à6 共67元
显然1à2重复走了一次,目的是为了先到达城市4,从而使得2à3这段路的费用从100缩减到10元。
看到这里很多同学好像就恍然大悟,但是问题马上又来了。如果同一条路允许重复走,那么就不能标记了,
但一旦不标记,失去了搜索的限制条件,DFS就无法结束,不是陷入死循环了?
我刚才说这种思路“对一半,错一半”,“对”是对在“重复走会增加费用”,“错”是错在“重复走的
对象不是某一条路,而是某一个环路”。在同一个环路重复走才会真正增加费用。但是标记环路是很麻烦的,
那么能不能根据某一条路或某一个城市重复走过的次数来判断当前所走的方案已经出现了环路? 答案是可以的。
上述的例子已经验证过了,同一条路可以重复走,但是不能无限重复走,重复的次数是有限的。那么应该重复
多少次才合理?这与m值有关。题目的m值范围为<=10,那么当人一个城市被到达的次数若 >3次(不包括3),
所走的方案必然出现了环路(网上的同学称之为“闸数”)。
因此只需把bool vist[] 修改为 int vist[] 进行标记,本题就能解决了。
#include"stdio.h"
#include"string.h"
int visit[1000],n,m;
#define inf 99999999
int min;
struct point
{
int x,y,z,w,v;
}a[1000];
void bfs(int k,int cost)
{
int i;
if(k==n&&cost<min)
{
min=cost;
return ;
}
for(i=0;i<m;i++)
{
if(a[i].x==k&&visit[a[i].y]<3)
{
visit[a[i].y]++;
if(visit[a[i].z]==0)
bfs(a[i].y,cost+a[i].v);
else
bfs(a[i].y,cost+a[i].w);
visit[a[i].y]--;
}
}
}
int main()
{
int i,j;
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=0;i<m;i++)
scanf("%d%d%d%d%d",&a[i].x,&a[i].y,&a[i].z,&a[i].w,&a[i].v);
memset(visit,0,sizeof(visit));
min=inf;
bfs(1,0);
if(min==inf)
printf("impossible\n");
else
printf("%d\n",min);
}
return 0;
}
这篇关于poj 3411 Paid Roads的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!