@洛谷的链接
题目描述
给定一张(n)个点,(m)条边的有向图,每条为白色或者黑色,只有出发点和边为相同颜色时才能通行。求一种对点的标色方案,使得最短路的最大,也可以选择被困在这张图中出不去(-1)。
思路
考虑反向建边,这样就可以使得边的颜色和点的颜色一致。如果能够有一种方案被困在图中,那么就尽可能的困在图中。所以对于一个点有以下情况:
(w[x]):该点为白色时到该点的最短距离,(w[x] = min(w[x], f[x] + 1))
(b[x]):该点为黑色时到点的最短距离,(b[x] = min(b[x], f[x]+1))
(f[x]):到该点时,(w[x])和(b[x])更大的值,当且仅当(w[x])和(b[x])都存在时才更新。(如果有一种方式达不到,就说明可以留在图中)。
最后的答案也是对(f[1])的判断。染色就很容易,对于一个点,如果(w[x]>b[x]),就染白色,否则染成黑色。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int N = 5e5 + 10;
vector<int> be[N], we[N];
int f[N], w[N], b[N];
bool inq[N];
void solve() {
int n, m;
cin >> n >> m;
for(int i = 1; i <= m; i++) {
int v, u, op;
scanf("%d%d%d", &v, &u, &op);
if(op == 1) {
we[u].push_back(v);
} else {
be[u].push_back(v);
}
}
memset(f, 0x3f, sizeof f);
memset(w, 0x3f, sizeof f);
memset(b, 0x3f, sizeof f);
queue<int> q;
q.push(n);
f[n] = w[n] = b[n] = 0;
while(!q.empty()) {
int u = q.front(); q.pop();
inq[u] = false;
for(int i = 0; i < we[u].size(); i++) {
int v = we[u][i];
if(w[v] > f[u] + 1) {
w[v] = f[u] + 1;
if(max(w[v], b[v]) < inf) {
f[v] = max(w[v], b[v]);
if(!inq[v]) {
inq[v] = true;
q.push(v);
}
}
}
}
for(int i = 0; i < be[u].size(); i++) {
int v = be[u][i];
if(b[v] > f[u] + 1) {
b[v] = f[u] + 1;
if(max(b[v], w[v]) < inf) {
f[v] = max(w[v], b[v]);
if(!inq[v]) {
inq[v] = true;
q.push(v);
}
}
}
}
}
if(f[1] == inf) puts("-1");
else printf("%d
", f[1]);
for(int i = 1; i <= n; i++) {
if(w[i] > b[i]) printf("1");
else printf("0");
}
}
int main() {
// freopen("in.txt", "r", stdin);
solve();
return 0;
}