深搜+dijkstra_Poj_1062_昂贵的聘礼

//本来打算练个最短路的 但看到题目有”等级“限制,就改成用深搜做了。 (32Ms)
//因为把等级这个元素放入DFS函数中进行比放到节点中实现要方便的多
//PS:网上找来了这题 的dijkstra,挺好的,又短又高效,注释了下(0Ms)

                                                              /*深搜解法*/
#include<iostream>
using namespace std;
#define Max 999999999;
//定义相连表节点结构
struct Edge{
int dest,value;
Edge *link;
};

Edge *edge[100];//定义相连表,以及一个指针

int M,N;//地位等级差距和物品总数

//定义个实际节点
struct Node{
int P,L,X;
int D;//表示最短路
};

Node node[100];//定义实际节点对象

//深搜
void dfs(int max_level,int min_level,int now_i,int lenth_sum)
{
node[now_i].D=lenth_sum;
Edge *l=edge[now_i];
int tmax_level,tmin_level;//存储下一个节点的最大最小Level
while(l)
{
//判断当前状态下可否访问下一个节点(就是考虑level)
if(max_level - node[l->dest].L <=M && node[l->dest].L - min_level <=M)
{
//下一节点的权限设置好
tmax_level = max_level,tmin_level = min_level;
if(node[l->dest].L > max_level)
tmax_level = node[l->dest].L;
else if(node[l->dest].L < min_level)
tmin_level = node[l->dest].L;
//搜索子节点
       if(node[now_i].D+l->value<node[l->dest].D)//如果该点长度加上下一路径小于子节点的D
dfs(tmax_level,tmin_level,l->dest,node[now_i].D+l->value);
}
l = l->link;
}
}

int main()
{
int P,L,X;
while(cin>>M>>N)
{
int i,j;
for(i=0;i<N;i++)
edge[i]=NULL;//初始化原始链表
Edge *l;
for(i=0;i<N;i++)
{
cin>>P>>L>>X;
node[i].P=P,node[i].L=L,node[i].X=X,node[i].D=Max;//初始化实际节点
//初始化相连链表
int dest,value;
for(j=0;j<X;j++)
{
cin>>dest>>value;
l=new Edge;
l->dest=dest-1;
l->value=value;
l->link=edge[i];
edge[i]=l;
}
}
node[0].D=0;
//深搜
dfs(node[0].L,node[0].L,0,0);
//找出最小的并输出
int value = 999999999;
for(i=0;i<N;i++)
if(node[i].P+node[i].D < value)
value = node[i].P+node[i].D;
printf("%d\n",value);
}
return 0;
}


                                                                 /*dijkstra算法_相连矩阵(0Ms)*/

#include<stdio.h>
#include<string.h>
#define INF 1<<30//2的29次方
//w:,p:价格,d:最短路径,sta:等级, v:可访问的点是否已经访问过,de:可访问性
int w[101][101],p[101],d[101],sta[101],v[101],de[101];
int main() {
int M,N,i,j,k; scanf("%d %d",&M,&N);
for(i=1;i<=N;i++)
{
for(j=1;j<=N;j++)
w[i][j]=INF;
}
int t1,t2,num,n,price;
//初始化
for(i=1;i<=N;i++)
{
scanf("%d %d %d",&p[i],&sta[i],&num);
for(j=0;j<num;j++)
{
scanf("%d %d",&n,&price); 
w[i][n]=price;//初始化相连矩阵
}
}
int ans=INF;
int bottom=sta[1]-M;//所有可能性的设置等级底限
for(k=bottom;k<=sta[1];k++)//等级底限可变动,因为低等级的可不取转而要高等级
{
//初始化最短路径d
d[1]=0;
for(i=2;i<=N;i++)
d[i]=INF;
t1=k;t2=t1+M;//高等级的上限是sta[1]+M
int s=N;
memset(v,0,sizeof(v));
memset(de,1,sizeof(de));//记录是否可访问
//计算出当前权限范围内可访问的个数S
for(i=2;i<=N;i++)
{
if(sta[i]<t1||sta[i]>t2)
{
de[i]=0;
s--;
}
}
//dijkstra算法
for(i=1;i<=s;i++){
int x,m=INF;
for(j=1;j<=N;j++)
if(de[j]&&!v[j]&&d[j]<m)
m=d[x=j];//复合句,挺好的
v[x]=1;
for(j=1;j<=N;j++)
if(de[j]&&d[j]>d[x]+w[x][j]) d[j]=d[x]+w[x][j];
}
for(i=1;i<=N;i++)
if(de[i]&&d[i]+p[i]<ans) ans=d[i]+p[i];
}
printf("%d\n",ans);
return 0;
}
出自:http://blog.csdn.net/agralol/article/details/5835771


                                               /*dijkstra_相连表(16Ms)*/

//学了上面的例子,知道等级可以这样处理 ,于是用相连表做了遍

#include<iostream>
using namespace std;
#define Max_value 999999999;
int M,N;
struct Edge{
int dest,value;
Edge *link;
}*edge[101],*l;//相连链表和一个活动指针
struct Node{
int P,L,D,least_D;
bool IsInLevel,IsBeen;
}node[101];//节点


int main()
{
int i,j,num;
while(cin>>M>>N)
{
//初始化节点和链表
for(i=1;i<=N;i++)
{
cin>>node[i].P>>node[i].L>>num;
node[i].least_D = Max_value;
edge[i] = NULL;//相连链表初始为空
for(j=0;j<num;j++)
{
l= new Edge;
cin>>l->dest>>l->value;
l->link=edge[i];
edge[i]=l;
}
}
int bottom_level = node[1].L - M;
for(i=bottom_level;i<=node[1].L;i++)//执行dijkstra算法的次数
{
if(i<0) continue;//因为L非负,可剪枝
int max_level = i+M,min_level=i;
int sum = N;//记录可进行操作的个数
for(j=1;j<=N;j++)
{
node[j].D = -1;
node[j].IsBeen = false;
if(node[j].L<min_level||node[j].L>max_level)
{
node[j].IsInLevel = false;
sum--;
}
else node[j].IsInLevel = true;
}
//开始执行dijkstra算法
node[1].D=node[1].least_D=0;
int k;
for(k=1;k<=sum;k++)//将顶点最短路标记为到达,执行sum次
{
int min_i=1,min_value;
min_value = Max_value;
for(j=1;j<=N;j++)
{
if(node[j].IsInLevel && !node[j].IsBeen && node[j].D>=0 && node[j].D<min_value)
min_value=node[min_i=j].D;
}
if(min_i==1 && node[1].IsBeen) break;//这个剪枝可以从64Ms到16Ms,说明有些点是不可达到的
l=edge[min_i];
while(l)
{
int dest = l->dest;
if(node[dest].IsInLevel && !node[dest].IsBeen && (node[dest].D<0|| node[dest].D>node[min_i].D + l->value))
node[dest].D=node[min_i].D + l->value;
l = l->link;
}
if(node[min_i].D<node[min_i].least_D) node[min_i].least_D=node[min_i].D;
node[min_i].IsBeen = true;
}
}
//输出
int min_cost = Max_value;
for(i=1;i<=N;i++)
if(node[i].least_D!=999999999 && min_cost>node[i].least_D + node[i].P)
min_cost = node[i].least_D + node[i].P;
printf("%d\n",min_cost);
}
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值