[题解]UVA10917 Walk Through the Forest

#1.0 理解题意

本题最需要理解的是这句话:

如果有一条从B到他的家的路线比从A到他的家的任何可能的路线都短,那么他认为从A到B更好。

\(d_x\) 表示 \(x\)\(2\) 号节点的最短路,那么上文的意思就是如果 \(A,B\) 间存在道路且 \(d_B<d_A\),那么道路 \(A\to B\) 便是一种可行的选择。

#2.0 大体思路

根据上面那句话,我们便需要先处理出所有点到 \(2\) 号点的最短距离。然后按照上面的要求重新建图,这里建出的边是单向边,再注意到得到的图是一张有向无环图\(\texttt{DAG}\)),因为每条边的边权都是非负数,用反证法不难证明得到的最短路图不存在环。

此时考虑 \(\texttt{DAG}\) 上的动态规划,设 \(sum_x\) 表示从 \(1\) 号节点到 \(x\) 号节点可行的路径条数,显然有

\[sum_x=\sum\limits_{(y,x)\in E}sum_y. \]

这里 \(E\) 表示边集,有序数对 \((u,v)\) 表示一条从 \(u\)\(v\) 的有向边。边界为 \(sum_1=1.\)

同时注意到,节点 \(1\) 不一定是入度为 \(0\) 的点,入度为零的点除 \(1\) 外不会对答案造成贡献。

拓扑结束后得到的结果便是本题所求。

#define pii pair<int, int>
#define mp(a, b) make_pair(a, b)
#define mset(l, x) memset(l, x, sizeof(l))

const int N = 100010;
const int INF = 0x7fffffff;

struct Edge {
    int u, v, w;
    int nxt;
};
Edge e[N], ne[N];

int cnt = 1, ncnt = 1, head[N], nhead[N];
int dist[N], vis[N], tot[N], s, t, icnt[N];
int qx[N], frt, tal, tag[N], n, m;

priority_queue <pii > q;

inline void add(const int &u, const int &v, const int &w) {
    e[cnt].u = u, e[cnt].v = v, e[cnt].w = w;
    e[cnt].nxt = head[u], head[u] = cnt ++;
}

inline void addn(const int &u, const int &v) {
    ne[ncnt].u = u, ne[ncnt].v = v, icnt[v] ++;
    ne[ncnt].nxt = nhead[u], nhead[u] = ncnt ++;
}

void Dijkstra() {
    mset(dist, 0x3f);
    q.push(mp(0,2)); dist[2] = 0;
    while (q.size()) {
        int now = q.top().second; q.pop();
        if (vis[now]) continue;
        vis[now] = true;
        for (int i = head[now]; i; i = e[i].nxt)
          if (dist[e[i].v] > dist[now] + e[i].w) {
              dist[e[i].v] = dist[now] + e[i].w;
              q.push(mp(-dist[e[i].v], e[i].v));
          }
    }
}

inline void clear() {
    frt = 0, tal = -1; 
    ncnt = cnt = 1; mset(tot, 0);
    mset(icnt, 0); mset(tag, 0);
    mset(vis, 0); mset(dist, 0x3f);
    mset(head, 0); mset(nhead, 0);
}

void topo() {
    mset(vis, 0);
    for (int i = 1; i <= n; i ++) 
      if (!icnt[i] || i == 1) qx[++ tal] = i;
    tag[1] = tot[1] = vis[1] = 1;
    while (frt <= tal) {
        int now = qx[frt ++];
        for (int i = nhead[now]; i;i = ne[i].nxt) {
            icnt[ne[i].v] --;
            if (tag[now]) {
                tot[ne[i].v] += tot[now], 
                tag[ne[i].v] |= tag[now];
            }
            if (!icnt[ne[i].v] && !vis[ne[i].v]) {
                qx[++ tal] = ne[i].v;
                vis[ne[i].v] == true;
            }
        }
    }
}

int main() {
    scanf("%d", &n);
    while (n) {
        scanf("%d", &m); s = 1, t = 2; clear();
        for (int i = 1; i <= m; i ++) {
            int u, v, w; scanf("%d%d%d", &u, &v, &w);
            add(u, v, w); add(v, u, w);
        }
        Dijkstra();
        for (int i = 1; i <= n; i ++)
          for (int j = head[i]; j; j = e[j].nxt)
            if (dist[i] > dist[e[j].v])
              addn(i, e[j].v);
        topo();
        printf("%d\n", tot[t]);
        scanf("%d", &n);
    }
    return 0;
}

End

希望能为各位带来帮助。

posted @ 2021-07-08 19:19  Dfkuaid  阅读(57)  评论(0编辑  收藏  举报