题目链接
题意:现在有n点m条路,要求你从1走到n,但是每条道路都有一个属性,1表示这条路可以走,0表示这条路在施工不能走,要你选择一条从1走到n的最短路,如果最短路上有道路的属性是0的话就要修好这条路,同时要破坏掉不是最短路径上的路,问你最少的操作数是多少(操作数是指要破坏的道路数和要修的道路数)。同时还要输出你的操作(就是要把你破坏的道路和修好的道路输出)。
思路:这个真是个阅读理解题,都半天也没读懂到底要输出什么,读懂题意的话很好做,操作数=最短路径总条数-最短路径上属性是1的条数+图的总条数-最短路径上属性是1的条数,那么就是d【n】+sum-2*cnt1,要是这个最小的话,很显然就是要找属性1的道路尽可能多的路。
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+1;
int n,m,d[maxn],num[maxn],u[maxn],v[maxn],w[maxn],pre[maxn],sum=0;
bool vis[maxn];
vector<pair<int,int>>g[maxn];
void spfa(int x)
{
memset(vis,false,sizeof(vis));
for(int i=0;i<=n;++i) d[i]=0x3f3f3f3f;
d[x]=0;num[x]=0;
queue<int>q;
q.push(x);
vis[x]=true;
while(!q.empty())
{
int top=q.front();
q.pop();
vis[top]=false;
for(auto v:g[top])
{
if(d[top]+1<d[v.first]||(d[top]+1==d[v.first]&&num[top]+v.second>num[v.first]))
{
d[v.first]=d[top]+1;
pre[v.first]=top;
num[v.first]=num[top]+v.second;
if(!vis[v.first]) q.push(v.first),vis[v.first]=true;
}
}
}
}
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=m;++i)
{
scanf("%d %d %d",&u[i],&v[i],&w[i]);
g[u[i]].push_back({v[i],w[i]});
g[v[i]].push_back({u[i],w[i]});
sum+=w[i];
}
spfa(1);
printf("%d\n",d[n]+sum-2*num[n]);
memset(vis,false,sizeof(vis));
int t=n;vis[1]=true;
while(t!=1) vis[t]=true,t=pre[t];
for(int i=1;i<=m;++i)
{
if(w[i]&&(!vis[u[i]]||!vis[v[i]])) printf("%d %d 0\n",u[i],v[i]);//不在最短路径上的需要破坏的
else if((pre[u[i]]==v[i]||pre[v[i]]==u[i])&&vis[u[i]]&&vis[v[i]]&&!w[i]) printf("%d %d 1\n",u[i],v[i]);//在最短路径上的需要修复的
}
}