Description
Input
Output
Sample Input
1 4 10000 3 2 2 8000 3 5000 1000 2 1 4 200 3000 2 1 4 200 50 2 0
Sample Output
5250
这道题的意思简洁明了,但是我就是不会做,练图论也有一段时间了,但是这种POJ上10000多人AC的题目我却还是无法第一时间入手,真的是深感惭愧。实在是太弱了。
后来写着写着终于写出来了。大概思路就是:
第一点,要明白,已知酋长的等级level[1],和最大等级差距d_val,那么所以能交易的人的等级都是在【level[1]-d_val , level[1]+d_val】之间的。
第二点,要明白,比如酋长等级是4,d_val = 3,那么用dijkstra的时候要保证选取交易的人等级是在【1,7】里面选的,然后和一个等级为7的人交易,那么此时能交易的人变成了【4,7】,再和一个等级为6的人交易,依然是【4,7】的范围。但是,如果我是先和等级6的人交易,那么范围是【3,7】,再和等级为7的人交易,那么范围是【4,7】,此时是需要去变的!和等级小于酋长等级的人交易时也有这样的关系。
第三点,依然要明白,这个图,不能正着建,比如样例中,我要先买4号物品,才能以200的价格买3号物品,再以5000价格买1号物品,所以其实这个是单连通图,是单向的,你要从后面的点向前面走。所以,要反着建,存入矩阵中。
如果没有等级限制,这道题实在是太简单了,但是他现在就是有等级限制。说了这么多,直接贴代码看看我是怎么处理等级限制的。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAX 9999999
#define LEN 105
int map[LEN][LEN]; //某点到某点两点间的的距离
int dist[LEN]; //记录当前点到源点的最短路径长度
int mark[LEN]; //加入进来的点的集合
int level[LEN];//各个交易者的等级
int d_val;//最大等级差距
void init()
{
int i,j;
for(i=0;i<LEN;i++)
{
for(j=0;j<LEN;j++)
{
map[i][j]=MAX;
}
}
}
void myDijkstra(int n,int start)
{
int min_level[LEN],max_level[LEN];
int i,j,min,pos;
for(i = 1; i <= n; i++)
{
mark[i]=0;
dist[i]=map[i][i];
if(level[i]<=level[1]+d_val&&level[i]>=level[1]-d_val)//如果这个交易者没有超出限制
{ //那么就直接赋值一开始的等级限制
min_level[i] = level[1] - d_val;
max_level[i] = level[1] + d_val;
}
else//否则这个交易者不能通过,直接排除掉
mark[i] = 1;
}
for(i = 1; i <= n; i++)
{
min = MAX;
for(j = 1; j <= n; j++)
{
if(!mark[j] && dist[j] < min && min_level[j] <= level[1] && level[1] <= max_level[j])
{ //取出不在mark里的最小的dist[i]
min = dist[j];
pos = j;//标记
}
}
if(min==MAX)//已经不能通了
break;
mark[pos] = 1;
if(level[pos] > level[1])
{
if(min_level[pos] < level[pos] - d_val)
min_level[pos] = level[pos] - d_val;
}
else
{
if(max_level[pos] > level[pos] + d_val)
max_level[pos] = level[pos] + d_val;
}
//做松弛操作
for(j = 1; j <= n; j++)
{
if(!mark[j] && dist[j] > dist[pos] + map[pos][j] && max_level[pos] >= level[j] && level[j] >= min_level[pos])
{
dist[j] = dist[pos] + map[pos][j];
min_level[j] = min_level[pos];
max_level[j] = max_level[pos];
if(level[j] > level[1])
{
if(min_level[j] < level[j] - d_val)
min_level[j] = level[j] - d_val;
}
else
{
if(max_level[j] > level[j] + d_val)
max_level[j] = level[j] + d_val;
}
}
}
}
}
int main()
{
int i,n;
int a,b,c;
scanf("%d%d",&d_val,&n);//输入点和多少个路
init();
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&a,&b,&c);
map[i][i] = a;
level[i] = b;
while(c--)
{
scanf("%d%d",&a,&b);
if(map[a][i] > b)
map[a][i] = b;
}
}
myDijkstra(n,1);//调用方法(点数,起始点)
cout << dist[1] << endl;
return 0;
}