標籤:最短路
連結: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|1struct 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;}