题意:给你一些道路,道路长度都为1,道路有两个状态可用和不可用。 寻找一条1到N的最短路,使得该最短路上的道路全部可用,其他道路全部不可用,要求改变状态的道路数量尽量小。
分析:1-N的最短路的长度一定是确定的,设为最短路长度D,设最短路上可用的道路数量为X,所有道路中可用的数量为Y。 那么需要改变的数量就是D-X+Y-X =D+Y-2X。
D与Y都为常量,所以我们要使得X尽量大。对于某边是否可能在最短路上我们可以用dis[u]+1==dis[v]验证。然后对于在最短路上的边,我们可以dp求X的最大值。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int INF = 0x7fffffff;
const int N = 2e5 + 10;
const int MOD = 1e9 + 7;
struct edge {
int v, c;
edge() {}
edge(int v, int c): v(v), c(c) {}
};
map<pair<int, int>, int> M;
vector<edge> G[N];
queue<int> Q;
int n, m, x[N], y[N], c[N];
int dis[N], dp[N], pre[N];
int ax[N], ay[N], ac[N];
bool vis[N];
int main() {
#ifdef Tally_Ho
freopen("in.txt", "r", stdin);
#endif // Tally_Ho
scanf("%d%d", &n, &m);
for(int i = 0; i < m; i++) {
scanf("%d%d%d", &x[i], &y[i], &c[i]);
G[x[i]].push_back(edge(y[i], c[i]));
G[y[i]].push_back(edge(x[i], c[i]));
}
Q.push(1);
while(!Q.empty()) {
int u = Q.front();
Q.pop();
for(int i = 0; i < G[u].size(); i++) {
int v = G[u][i].v;
int c = G[u][i].c; //1:working
if(!vis[v]) {
dis[v] = dis[u] + 1;
vis[v] = 1;
Q.push(v);
}
if(dis[v] == dis[u] + 1 && dp[u] + c >= dp[v]) {
pre[v] = u;
dp[v] = dp[u] + c;
}
}
}
int v = n;
while(v != 1) {
M[make_pair(v, pre[v])] = 1;
v = pre[v];
}
int len = 0;
for(int i = 0; i < m; i++) {
bool onRoad = M[make_pair(x[i], y[i])] || M[make_pair(y[i], x[i])];
if(onRoad && c[i] == 0) {
ax[len] = x[i], ay[len] = y[i], ac[len++] = 1;
} else if(!onRoad && c[i] == 1) {
ax[len] = x[i], ay[len] = y[i], ac[len++] = 0;
}
}
printf("%d\n", len);
for(int i = 0; i < len; i++)
printf("%d %d %d\n", ax[i], ay[i], ac[i]);
return 0;
}