题目大意:给无向简单连通图的m条边,求从顶点1到顶点n的最短路,同时使得最短路径中标记为0的边数与不在最短路径中标记为1的边数之和最小,输出这些边。
//可以设边权为1,使用优先队列,当前路径长度小的优先,路径长度相等时,最短路径中标记为0的边少的优先。
#include<bits/stdc++.h>
using namespace std;
#define maxn 100005
struct Edge
{
int x,y,z;
}edge[maxn<<1];
struct Node
{
int v,dis,num,pre;
}node[maxn];
struct cmp
{
bool operator() (Node &x,Node &y)
{
return x.dis>y.dis||(x.dis==y.dis&&x.num>y.num);
}
};
vector<int>g[maxn];
bool vis[maxn];
bool used[maxn<<1];
int n,m;
priority_queue<Node,vector<Node>,cmp> Q;
void solve()
{
Node temp=Node{1,1,0,-1};
int i;
Q.push(temp);
memset(vis,0,sizeof(vis));
while(!Q.empty())
{
temp=Q.top();Q.pop();
if(vis[temp.v]) continue;
vis[temp.v]=1;
node[temp.v]=temp;
if(temp.v==n) break;
for(i=0;i<g[temp.v].size();++i)
{
int j=g[temp.v][i];
if(vis[edge[j].y]) continue;
if(edge[j].z) Q.push(Node{edge[j].y,temp.dis+1,temp.num,j});
else Q.push(Node{edge[j].y,temp.dis+1,temp.num+1,j});
}
}
int ans=0;
memset(used,0,sizeof(used));
i=temp.pre;
while(i!=-1)
{
used[i]=1;
i=node[edge[i].x].pre;
}
for(i=1;i<=m+m;i+=2)
{
if(used[i]||used[i+1])
{
if(edge[i].z==0)
++ans;
}
else if(edge[i].z==1)
++ans;
}
printf("%d\n",ans);
for(i=1;i<=m+m;i+=2)
{
if(used[i]||used[i+1])
{
if(edge[i].z==0) printf("%d %d 1\n",edge[i].x,edge[i].y);
}
else if(edge[i].z==1) printf("%d %d 0\n",edge[i].x,edge[i].y);
}
}
int main()
{
int i;
cin>>n>>m;
for(i=1;i<=m+m;i+=2)
{
scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].z);
edge[i+1].x=edge[i].y;
edge[i+1].y=edge[i].x;
edge[i+1].z=edge[i].z;
g[edge[i].x].push_back(i);
g[edge[i+1].x].push_back(i+1);
}
solve();
return 0;
}