题目:
http://codeforces.com/problemset/problem/510/C
题意:
n个点m条边的无向图,求出从1->n的最短路,使得其路径上标记为0的路径最少,除了这条最短路径上的路,其他路都应标记为0. 求出需要修改标记的路径数量,及其每条路的端点和应修改的标记。
思路:
最短路dis数组表示最短路径,zer数组表示路径最短的情况下0标记最少的路径。
AC.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1e5+5;
int n, m;
struct Ans {
int u, v, d;
}ans[maxn];
int tot, head[maxn];
struct Edge{
int to, d, next;
}edge[maxn*2];
void addedge(int u, int v, int d)
{
edge[tot].to = v;
edge[tot].d = d;
edge[tot].next = head[u];
head[u] = tot++;
}
int dis[maxn], vis[maxn], zer[maxn], pre[maxn], prvv[maxn];
int spfa(int s)
{
fill(dis, dis + n + 1, inf);
memset(pre, -1, sizeof(pre));
memset(vis, 0, sizeof(vis));
queue<int> que;
que.push(s);
vis[s] = 1;
dis[s] = 0;
while(!que.empty()) {
int u = que.front(); que.pop();
vis[u] = 0;
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to, d = edge[i].d;
if(dis[v] > dis[u] + 1) {
dis[v] = dis[u] + 1;
zer[v] = zer[u] + d;
pre[v] = u;
if(!vis[v]) {
vis[v] = 1;
que.push(v);
}
}
else if(dis[v] == dis[u] + 1 && zer[v] < zer[u] + d) {
zer[v] = zer[u] + d;
pre[v] = u;
if(!vis[v]) {
vis[v] = 1;
que.push(v);
}
}
}
}
}
void init()
{
tot = 0;
memset(head, -1, sizeof(head));
}
int main()
{
// freopen("in", "r", stdin);
while(~scanf("%d%d", &n, &m)) {
init();
for(int i = 0; i < m; ++i) {
int u, v, d;
scanf("%d%d%d", &u, &v, &d);
addedge(u, v, d);
addedge(v, u, d);
}
spfa(1);
memset(prvv, -1, sizeof(prvv));
for(int i = n; ~i; i = pre[i]) {
prvv[i] = pre[i];
}
int cnt = 0;
for(int i = 0; i < tot; i+=2) {
int u = edge[i^1].to, v = edge[i].to, d = edge[i].d;
if((prvv[u] == v || prvv[v] == u) && d == 0) {
ans[cnt].u = u; ans[cnt].v = v; ans[cnt++].d = 1;
}
else if((prvv[u] != v && prvv[v] != u) && d == 1) {
ans[cnt].u = u; ans[cnt].v = v; ans[cnt++].d = 0;
}
}
printf("%d\n", cnt);
for(int i = 0; i < cnt; ++i) {
printf("%d %d %d\n", ans[i].u, ans[i].v, ans[i].d);
}
}
return 0;
}