E. Breaking Good
题意:一个无向图,边长度都是1,有些边是失效的。现在需要找一条从1到n的最短路径,路径上失效的边需要修改为有效的,非路径边如果有效要修改为失效的。输出需要修改的边,使得修改量最少。
思路:问题很容易转化为求最短路,路径上的有效边尽可能多。方法是先SPFA求每个点到点1的距离,然后再次SPFA计算点1到每个点的最短路径,最多有多少条有效边,并记录每个点的前驱。知道点1到点n最多有多少有效边后,就能知道需要修改的边的数量了。最后再次BFS,作相应的修改就可以了。
#include <iostream>
#include <stdio.h>
#include <string>
#include <map>
#include <vector>
#include <stack>
#include <queue>
#include <string.h>
#include <algorithm>
#include <math.h>
using namespace std;
const int maxn=100010;
struct edge{
int v,z;
edge(int v,int z):v(v),z(z){}
};
vector<edge> E[maxn];
int dis[maxn];
int cnt[maxn];
int pre[maxn];
bool use[maxn];
bool vis[maxn];
int main(){
int n,m;
cin>>n>>m;
for(int i=2;i<=n;i++){
dis[i]=1000000000;
cnt[i]=-1;
}
int sum=0;
for(int i=0;i<m;i++){
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
E[x].push_back(edge(y,z));
E[y].push_back(edge(x,z));
sum+=z;
}
dis[1]=0;
queue<int> que; que.push(1);
while(!que.empty()){
int cur=que.front(); que.pop();
int sz=E[cur].size();
for(int i=0;i<sz;i++){
int v=E[cur][i].v;
if(dis[cur]+1<dis[v]){
dis[v]=dis[cur]+1;
que.push(v);
}
}
}
que.push(1);
while(!que.empty()){
int u=que.front(); que.pop();
int sz=E[u].size();
for(int i=0;i<sz;i++){
int v=E[u][i].v;
if(dis[u]+1==dis[v]){
int tmp=cnt[u]+E[u][i].z;
if(tmp>cnt[v]){
cnt[v]=tmp;
pre[v]=u;
}
que.push(v);
}
}
}
int tmp=n;
while(tmp!=0){
use[tmp]=1;
tmp=pre[tmp];
}
int ans=(dis[n]-cnt[n])+(sum-cnt[n]);
cout<<ans<<endl;
que.push(1);
while(!que.empty()){
int u=que.front(); que.pop();
int sz=E[u].size();
vis[u]=1;
for(int i=0;i<sz;i++){
int v=E[u][i].v;
if(dis[u]<dis[v] || (dis[u]==dis[v]&&u<v) ){
if(pre[v]==u&&E[u][i].z==0&&(use[u]&&use[v])){
printf("%d %d %d\n",u,v,1);
}
if( (pre[v]!=u&&E[u][i].z==1) || (!(use[u]&&use[v])&&E[u][i].z==1) ){
printf("%d %d %d\n",u,v,0);
}
if(!vis[v])que.push(v);
vis[v]=1;
}
}
}
return 0;
}