首先这个题目问的是从\(1\)到\(n\)的路径问题.所以我们可以先将与这些路径无关的边权直接赋为你喜欢的数\(\in\{1,2\}\).
令\(dis[i]\)表示确定玩\(w[i]\)后从\(1\)到\(i\)的最短距离.
那么对于剩下的任意一条边\(\{u,v\}\),必定有\(1\leq dis[v]-dis[u]\leq2\).
其实也很好理解,就是\(1\leq w[i]\leq2\)并且每一条路径长度要相同.
如果\(dis[v]-dis[u]>2\)且\(dis[v]-dis[u]<1\),就一定出现了路径不同的边(\(w[i]\)无法弥补他们的差距).
于是我们就有了若干个约束.
于是将\(u\rightarrow v\)连一条\(1\)的边,将\(v\rightarrow u\)连一条\(-2\)的边.
跑差分约束即可.
#pragma GCC optimize(3) #include<bits/stdc++.h> #define il inline #define rg register #define gi read<int> #define pii pair<int, int> using namespace std; const int N = 1010, M = 5010; template<class TT> il TT read() { TT o = 0,fl = 1; char ch = getchar(); while (!isdigit(ch) && ch != '-') ch = getchar(); if (ch == '-') fl = -1, ch = getchar(); while (isdigit(ch)) o = o * 10 + ch - '0', ch = getchar(); return fl * o; } queue<int>Q; pii book[M]; int mp[N][N], n, m, dis[N], cnt[N]; bool vis[2][N], mark; il void dfs(int u) { vis[mark][u] = 1; for (int v = 1; v <= n; ++v) if (mp[u][v] && !vis[mark][v]) vis[mark][v] = 1, dfs(v); } il void spfa() { memset(dis, -63, sizeof dis); Q.push(1); cnt[1] = 1; dis[1] = 0; while (!Q.empty()) { int u = Q.front(); Q.pop(); for (int v = 1; v <= n; ++v) if (mp[u][v] && dis[v] < dis[u] + mp[u][v]) { dis[v] = dis[u] + mp[u][v]; Q.push(v); cnt[v]++; if (cnt[v] > n) exit(puts("No") & 0); } } } int main() { n = gi(), m = gi(); for (int i = 1; i <= m; ++i) { int u = gi(), v = gi(); book[i] = pii(u, v); mp[u][v] = 1; } mark = 0; dfs(1); for (int i = 1; i <= m; ++i) { mp[book[i].first][book[i].second] = 0; mp[book[i].second][book[i].first] = 1; } mark = 1; dfs(n); for (int i = 1; i <= m; ++i) { int u = book[i].first, v = book[i].second; mp[v][u] = 0; if (vis[0][u] && vis[1][u] && vis[0][v] && vis[1][v]) mp[u][v] = 1, mp[v][u] = -2; // else printf("%d\n", i); } spfa(); puts("Yes"); for (int i = 1; i <= m; ++i) { int u = book[i].first, v = book[i].second; if (mp[u][v]) printf("%d\n", dis[v] - dis[u]); else puts("2"); } return 0; }