题目大意
有n座城市和m(1<=n,m<=10)条路。现在要从城市1到城市n。有些路是要收费的,从a城市到b城市,如果之前到过c城市,那么只要付P的钱,如果没有去过就付R的钱。求的是最少要花多少钱。
注意:路径是有向的。
算法思想:dfs可过。
提示:最优解法不是每条路只允许走一遍,可能有情况满足某条路i的p比r小很多,而且走c城市再回来走总钱数比直接走、付费r更省,此时只走i的“最短路”就不是最优解。每条路都可以重复走,那么为了防止出现死循环,当判断出途中有环时应当跳出。当某座城市走过3次以上时,可以判定陷入环中,应当跳出(至于为啥是3次。。。参考其他博主的文章,这与m的取值有关,本题中m<=10所以是3)。
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
using namespace std;
const int inf=21000000;
int n,m,ans,mx,vis[15],v[15],num=0; //因为判断是否能走的条件是走过的次数,这里vis[]用int型;
struct mc
{
int a,b,c,p,r,ne;
}e[15];
void put(int a,int b,int c,int p,int r)
{
num++;
e[num].a=a;
e[num].b=b;
e[num].c=c;
e[num].p=p;
e[num].r=r;
e[num].ne=v[a];
v[a]=num;
}
void dfs(int i,int ans) //dfs(当前城市,当前花费);
{
if (i==n) //到达目的地,判断这条路径是否最优;
{
if (ans<mx) mx=ans;
return;
}
for (int l=v[i];l;l=e[l].ne)
{
if (vis[e[l].b]<=3) //判环,确定是否可以继续走;
{
vis[e[l].b]++;
if (vis[e[l].c]) //满足要求,这条路付费p;
dfs(e[l].b,ans+e[l].p);
else //不满足要求,这条路付费r;
dfs(e[l].b,ans+e[l].r);
vis[e[l].b]--; //回溯;
}
}
return;
}
int main()
{
int a,b,c,p,r;
scanf("%d%d",&n,&m);
for (int i=1;i<=m;i++)
{
scanf("%d%d%d%d%d",&a,&b,&c,&p,&r);
put(a,b,c,p,r);
}
ans=0; mx=inf;
vis[1]=1;
dfs(1,0);
if (mx==inf) printf("impossible"); //最小花费未被更新,说明不能走到;
else printf("%d",mx);
return 0;
}