现在的位置: 首页 > 综合 > 正文

POJ–1062–昂贵的聘礼【dijkstra_heap+枚举】最短路

2018年04月24日 ⁄ 综合 ⁄ 共 2456字 ⁄ 字号 评论关闭

链接: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;
}

抱歉!评论已关闭.