Codeforces Round #287 (Div. 2) E. Breaking Good(最短路spfa)

题目链接
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
题意:现在有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]);//在最短路径上的需要修复的 
	}
}
发布了283 篇原创文章 · 获赞 0 · 访问量 7297

猜你喜欢

转载自blog.csdn.net/qq_42479630/article/details/105126525