链接:http://poj.org/problem?id=1062
题意不说了,中文的
“但是如果他和某个地位较低的人进行了交易,地位较高的的人不会再和他交易,他们认为这样等于是间接接触,反过来也一样。” 这句话一开始没懂,看discuss里说的之后才明白,实际上你能交易的等级范围为 l[i]~l[i]+m,或者l[i]-m~l[i],其中l[i]是第i个人的等级,m是等级差距限制。
这道题建图,如果对于第 i 个人来说,j 可以通过物品 + t 来交易第 i 个人的物品,则在他们之间建一条有向路径,方向 j → i ,权值 t ,然后新增一个节点0,从0到任何一点都有一条单向路径,权值为那一点本身的价值。我们要做的就是从0点出发,找到到达1点的最小值,即dist[1]。
但是等级限制是个问题,刚开始没想到,看了别人的解题报告,大部分人是枚举,以第i个人的等级为上限(也可以为下限),如果剩下的人里有等级比他高的,就标记为已访问,如果有等级比他低的超过了m的,也标记为已访问,找最短路时就不做处理。然后枚举以这n个人的等级为最大值的最短路情况,找到最小的dist[1]。
需要注意的是:
1. 每次标记时会标记vis数组1~n的值,但是不会标记0,0需要自己手动标记,因为这个WA了一发。
2. 还有就是dijkstra_heap的优先队列里,找到邻接表比较路径长度时没有判断出边的点是否已访问,因为前几次都没加所以也没有注意,WA了一发,直到发现discuss里有组数据过不了:
1 5
10000 3 3
2 8000
3 5000
5 1000
1000 2 1
4 200
3000 2 1
4 200
50 2 0
50 6 0
正解是5250。方式为4→3→1。
而我的输出是1050,因为枚举第五个人的时候,其他四个由于不符合等级限制都被标记了已访问,但是0没被访问,0还是走一遍,发现5未被标记,5也入队,由于判断里没有判断出边的点是否已访问,5→1直接更新了dist[1],然后1入队,发现1已访问,才退出,但是此时dist[1]的值已是1050,所以得到了错误的答案。解决方法就是多加一个是否已访问的判断。
#include<cstring>
#include<string>
#include<fstream>
#include<iostream>
#include<iomanip>
#include<cstdio>
#include<cctype>
#include<algorithm>
#include<queue>
#include<map>
#include<set>
#include<vector>
#include<stack>
#include<ctime>
#include<cstdlib>
#include<functional>
#include<cmath>
using namespace std;
#define PI acos(-1.0)
#define MAXN 100100
#define eps 1e-7
#define INF 0x7FFFFFFF
#define seed 131
#define ll long long
#define ull unsigned ll
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
struct node{
int u,v,next;
}edge[10100];
struct NODE{
int u,dis;
bool operator < (const NODE &t) const{
return t.dis<dis;
}
};
int vis[110],dist[110],head[110];
int n,m,cnt,p[110],l[110];
void add_edge(int a,int b,int c){
edge[cnt].u = b;
edge[cnt].v = c;
edge[cnt].next = head[a];
head[a] = cnt++;
}
void dijkstra_heap(){
int i,j;
NODE t1,t2;
for(i=0;i<=n;i++) dist[i] = INF;
dist[0] = 0;
vis[0] = 0;
t1.u = 0;
t1.dis = 0;
priority_queue<NODE>q;
q.push(t1);
while(!q.empty()){
t1 = q.top();
q.pop();
if(vis[t1.u]) continue;
vis[t1.u] = 1;
for(i=head[t1.u];i!=-1;i=edge[i].next){
int x = edge[i].v;
if(!vis[edge[i].u]&&dist[t1.u]+x<dist[edge[i].u]){ //没判断!vis[edge[i].u] WA出翔
dist[edge[i].u] = dist[t1.u] + x;
t2.u = edge[i].u;
t2.dis = dist[edge[i].u];
q.push(t2);
}
}
}
}
int main(){
int i,j,x,a,b;
while(scanf("%d%d",&m,&n)!=EOF){
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
cnt = 0;
for(i=1;i<=n;i++){
scanf("%d%d%d",&p[i],&l[i],&x);
while(x--){
scanf("%d%d",&a,&b);
add_edge(a,i,b);
}
}
for(i=1;i<=n;i++){
add_edge(0,i,p[i]);
}
int minm = INF;
for(i=1;i<=n;i++){
int mm = l[i];
for(j=1;j<=n;j++){
if(l[j]>mm||mm-l[j]>m) vis[j] = 1;
else vis[j] = 0;
//cout<<i<<" "<<vis[j]<<endl;
}
dijkstra_heap();
if(dist[1]<minm) minm = dist[1];
}
printf("%d\n",minm);
}
return 0;
}