题意:有n(n<=1000)个城市,m(m<=10000)条边,第i个城市油价为pi (pi<=100),每升油能行驶一公里,有q (q<=100)个询问,每个询问给出汽车油箱的容量c (c<=100),起点u,终点v,问从u到v最少花费是多少?
分析:每个城市加多少油是未知的,借鉴dijkstra算法,每个城市可以加1单位的油,也可以转移到其它城市,用优先级队列来存储,每次取费用最小的状态。
用b[i][j]表示到达点i,剩余油量为j的最小花费,避免无用计算。
一开始枚举了所有能加的油量,TLE。
const int N = 1001, M = 101; int p[N], b[N][M];//b[i][j] 到达点i,剩余油量j的最小花费 int n, m, query; int c, u, v, d; int head[N], pos; struct edge{ int v, next, d; }e[20005]; struct node{ int v, now, cost; }; struct cmp{ bool operator()(node a, node b){ return a.cost > b.cost; } }; priority_queue<node, vector<node>, cmp> q; void bfs(){ memset(b, -1, sizeof b); while(!q.empty()) q.pop(); node t, temp; t.cost = 0; t.v = u; t.now = 0; q.push(t); b[u][0] = 0; while(!q.empty()){ t = q.top(); q.pop(); if(b[v][0]!=-1 && b[v][0]<=t.cost) continue; if(b[t.v][t.now] < t.cost) continue; /*FOE(i, 1, c-t.now){//枚举能加的油量,超时。。 temp.v = t.v; temp.cost = t.cost + i*p[t.v]; temp.now = t.now + i; if(b[temp.v][temp.now] == -1 || b[temp.v][temp.now] > temp.cost){ b[temp.v][temp.now] = temp.cost; q.push(temp); } }*/ if(t.now < c){//加1单位油 temp.v = t.v; temp.cost = t.cost + p[t.v]; temp.now = t.now + 1; if(b[temp.v][temp.now] == -1 || b[temp.v][temp.now] > temp.cost){ b[temp.v][temp.now] = temp.cost; q.push(temp); } } for(int j = head[t.v]; j != -1; j = e[j].next){//转移到下一顶点 if(e[j].d <= t.now){ temp.v = e[j].v; temp.cost = t.cost; temp.now = t.now - e[j].d; if(b[temp.v][temp.now] == -1 || b[temp.v][temp.now] > temp.cost){ b[temp.v][temp.now] = temp.cost; q.push(temp); } } } } if(b[v][0] == -1) printf("impossible\n"); else printf("%d\n", b[v][0]); } int main(){ #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); #endif memset(head, -1, sizeof head); scanf("%d%d", &n, &m); FOR(i, 0, n) scanf("%d", &p[i]); FOR(i, 0, m){ scanf("%d%d%d", &u, &v, &d); e[pos].v = v; e[pos].next = head[u]; e[pos].d = d; head[u] = pos++; e[pos].v = u; e[pos].next = head[v]; e[pos].d = d; head[v] = pos++; } scanf("%d", &query); while(query--){ scanf("%d%d%d", &c, &u, &v); bfs(); } return 0; }