题目:ROADS POJ - 1724
题意:
有n个点(编号为1,2,3…n),有m条单向路,每条路有相应的长度l,以及每条路的过路费t
一个人要从1号点走到n号点,问在不超过花费mo的情况下最短路是多少。
思路:
利用邻接表去存每条边的信息
然后利用dfs暴搜即可。
构建邻接表:
add(ss,dd,ll,tt);
邻接表函数:
void add(int x,int y,int ll,int tt)
{
nx[head]=first[x];
first[x]=head;
l[head]=ll;
t[head]=tt;
to[head]=y;
head++;
}
//l,t,to具有相同的下标,可用结构体来存.
//便于理解就没有用到结构体
初始head=1;
邻接表建立,head在不断增加,相当于重新建立一个边的信息表.
first[x]中x表示顶点,而fisrt[x]为新的编号(新的信息表对应的标号),
假设head=first[x],那
y=to[head]就表示与x相连的点,
l[head]就表示x到y的长度,
t[head]就表示x到y的过路费
与顶点x相连的顶点可能有多个,因此这里在解释first,nx,to数组
下述所提的编号是题中所给m行边信息对应的编号
first[x]:
存储的就是以顶点x为始点的最后一条边所对应的编号,
设i=first[x],若i!=-1,则nx[i]存的是以x为始点倒数第二条边的编号,
...
nx数组:
根据上述所说,nx数组存储的是也是边的编号,作用就是寻找以x为始点的边的编号。
注意nx数组的下标不是顶点,而是m行中对应的某边的编号。
to数组:
存储的就是与始点x相连的顶点,所存的是顶点。注意to数组的下标也不是顶点,而是新建立的信息表中的编号。
建立双向邻接表与建立单向邻接表过程一致,始点和末点反转再调用一次即可。
代码:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
int first[101],nx[10001],to[10001],l[10001],t[10001],head;//n+1,m+1,m+1,m+1
int mo,n,m,minl,book[101];
void add(int x,int y,int ll,int tt)
{
nx[head]=first[x];
first[x]=head;
l[head]=ll;
t[head]=tt;
to[head]=y;
head++;
}
void dfs(int x,int suml,int sumt)
{
if(x==n)
{
minl=min(minl,suml);
return;
}
for(int i=first[x];i!=-1;i=nx[i])
{
int y=to[i];
if(!book[y]&&suml+l[i]<minl&&sumt+t[i]<=mo)
{
book[y]=1;
dfs(y,suml+l[i],sumt+t[i]);
book[y]=0;
}
}
}
int main()
{
while(~scanf("%d",&mo))
{
memset(first,-1,sizeof(first));
memset(book,0,sizeof(book));
scanf("%d %d",&n,&m);
int ss,dd,ll,tt;
for(int i=1;i<=m;i++)
{
scanf("%d %d %d %d",&ss,&dd,&ll,&tt);
add(ss,dd,ll,tt);
}
minl=INF;
book[1]=1;
dfs(1,0,0);
if(minl==INF)
printf("-1\n");
else
printf("%d\n",minl);
}
return 0;
}