链接: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; }
POJ--1062--昂贵的聘礼【dijkstra_heap+枚举】最短路