第二次来做这一题,由于题目中给定了一个等级限制M,所以可以通过枚举第一个点所在的位置求解.思路很清晰.
for (int i = 0; i <= M; ++i) 这个i来表示第一个点的等级在M长度区间内的偏移量.然后再在区间内建边,floyd即可.
代码如下:
#include <cstdlib> #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #define INF 0x3f3f3f3f using namespace std; int M, N, mey[105], lvl[105], head[105], idx; int lwall, rwall, G[105][105]; struct Edge { int v, val, next; }e[10005]; // 保留替换列表 void addedge(int x, int v, int val) { ++idx; e[idx].v = v, e[idx].val = val; e[idx].next = head[x], head[x] = idx; } inline bool in(int x) { if (lvl[x] >= lwall && lvl[x] <= rwall) { return true; } else return false; } void build() { memset(G, 0x3f, sizeof (G)); for (int i = 1; i <= N; ++i) { G[i][i] = 0; for (int j = head[i]; j != -1; j = e[j].next) { if (in(i) && in(e[j].v)) { G[i][e[j].v] = e[j].val; } } } } void floyd(int &ret) { for (int k = 1; k <= N; ++k) { for (int i = 1; i <= N; ++i) { for (int j = 1; j <= N; ++j) { if (G[i][k]!=-1&&G[k][j]!=-1) { // 有边相连 G[i][j] = min(G[i][j], G[i][k]+G[k][j]); } } } } for (int i = 1; i <= N; ++i) { if (G[1][i] != INF) { ret = min(ret, G[1][i]+mey[i]); } } } int main() { int c, v, val, ret; while (scanf("%d %d", &M, &N) == 2) { ret = INF; idx = -1; memset(head, 0xff, sizeof (head)); for (int i = 1; i <= N; ++i) { scanf("%d %d %d", &mey[i], &lvl[i], &c); for (int j = 1; j <= c; ++j) { scanf("%d %d", &v, &val); addedge(i, v, val); } } // 通过枚举第一个点在M区间的最左边和最右边 for (int i = 0; i <= M; ++i) { lwall = lvl[1]-i, rwall = lwall+M; if (lwall < 0) break; // 左边界不可能为负数 // 确定好了左右界在进行构边 build(); floyd(ret); } printf("%d\n", ret); } return 0; }