codeforces 287DIV2 E - Breaking Good(最短路)

题意:

给你n个点和m条道路,1表示道路没问题,0表示道路正在修,选取一条1->n的最短路,其中不属于最短路中的没问题的道路需炸毁,最短路上的需要修的道路我们要修好

求1到n之间的造成影响最小的最短路中会被影响的道路


方法:

因为走一条没问题的道路是不会造成影响的,走有问题的道路的是有影响的,所以我们在找最短路的时候,找到走没问题的道路的最多那一条即可,用迪杰斯特拉+堆优化 或者SPFA都行


PS:当时以为要影响最小然后最短,没想到是最短然后影响最小,我写了一下迪杰斯特拉+堆优化 和SPFA 发现所花时间差不多


代码1:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
#define maxm 200010
#define maxn 100010
#define INF 111111

struct node
{
	int a, b, c, next; 
	node(){}
	node(int a, int b, int c, int d):
		a(a),b(b),c(c),next(d){}
}edge[maxm];

struct pp
{
	int v, d1 ,d2;
	bool operator < (const pp &x) const
	{
		if(d1!= x.d1)
			return d1 > x.d1;
		return d2< x.d2;
	}
};

int n, m, tot;
int head[maxn], vis[maxn];
int dis[maxn], d[maxn], pre[maxn];
int ans[maxn];
priority_queue<pp> q;

void add(int x, int y, int z)
{
	edge[++tot]= node(x, y, z, head[x]);
	head[x]= tot;
}

void Dij()
{
	memset(d, 0, sizeof d);
	memset(vis, 0, sizeof vis);
	for(int i= 1; i< maxn; i++)
		dis[i]= INF;
	pp N;
	N.v= 1, N.d1= 0, N.d2= 0;	
	q.push(N);	
	while(!q.empty())
	{
		while(vis[N.v] && !q.empty())
		{
			N= q.top();
			q.pop();
		}			
		if(vis[N.v])
			break;
		vis[N.v]= 1;
		dis[N.v]= N.d1;
		d[N.v]= N.d2;
		for(int i= head[N.v]; i!= -1; i= edge[i].next)
			if(!vis[edge[i].b])
			{
				if(dis[N.v]+1< dis[edge[i].b] || (dis[N.v]+1 == dis[edge[i].b] && d[N.v]+edge[i].c> d[edge[i].b]))
				{
					pp M;
					M.v= edge[i].b;
					M.d1= dis[N.v]+1;
					M.d2= d[N.v]+edge[i].c;
					q.push(M);
					dis[edge[i].b]= M.d1;
					d[edge[i].b]= M.d2;
					pre[edge[i].b]= i;
				}
			}		
	}
	memset(ans, 0, sizeof ans);
	int xx= n;
	while(xx!= 1)
	{
		ans[(pre[xx]+1)/2]= 1;
		xx= edge[pre[xx]].a;
	}
}

int main()
{
	while(scanf("%d %d",&n,&m)!=EOF)
	{
		memset(head, -1, sizeof head);
		int x, y, z;
		tot= 0;
		int sum= 0;
		for(int i= 1; i<= m; i++)
		{
			scanf("%d %d %d",&x,&y,&z);	
			add(y, x, z);	
			add(x, y, z);
			if(z)sum++;
		}
		Dij();
		printf("%d\n",sum+dis[n]-2*d[n]);
		for(int i= 2; i<= 2*m; i+=2)
			if(ans[i/2]^edge[i].c)
				printf("%d %d %d\n",edge[i].a,edge[i].b,edge[i].c^1);				
	}
	return 0;
}


代码2:

#include <cstdio>
#include <cstring>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
#define maxn 100010
#define maxm 200010
#define INF 111111

struct node
{
	int a,v, c, next;
	node(){}
	node(int a,int v, int c, int next):
		a(a),v(v), c(c), next(next){}	
}edge[maxm];

struct pp
{
	int v,d1,d2;
};

queue<int> q;
int n, m, tot;
int dis[maxn], d[maxn], pre[maxn], ans[maxn], head[maxn];
int vis[maxn];

void add(int x, int y, int z)
{
	edge[++tot]= node(x, y, z, head[x]);
	head[x]= tot;
}

void SPFA()
{
	memset(d, 0, sizeof d);
	memset(ans, 0, sizeof ans);
	memset(vis, 0, sizeof vis);
	for(int i= 1; i<= maxn; i++)
		dis[i]= INF;
	dis[1]= 0;
	vis[1]= 1;
	q.push(1);
	while(!q.empty())
	{
		int v= q.front();
		q.pop();
		vis[v]= 0;	
		for(int i= head[v]; i!= -1; i= edge[i].next)
			if(dis[v]+ 1 < dis[edge[i].v] || (dis[v]+1== dis[edge[i].v] && d[v]+ edge[i].c> d[edge[i].v]))
			{
				dis[edge[i].v]= dis[v]+ 1;
				d[edge[i].v]= d[v]+ edge[i].c;
				pre[edge[i].v]= i;
				if(!vis[edge[i].v])
				{
					q.push(edge[i].v);
					vis[edge[i].v]= 1;
				}
			}
	}
	int xx= n;
	while(xx!= 1)
	{
		ans[(pre[xx]+1)/2]= 1;
		xx= edge[pre[xx]].a;
	}
}

int main()
{	
	while(scanf("%d %d",&n,&m)!=EOF)
	{
		tot= 0;
		int sum= 0, x, y, z;
		memset(head, -1, sizeof head);
		for(int i= 1; i<= m; i++)
		{
			scanf("%d %d %d",&x,&y,&z);
			add(y, x, z);
			add(x, y, z);
			if(z) sum++;
		}
		SPFA();
		printf("%d\n",sum+dis[n]-2*d[n]);
		for(int i= 2; i<= 2*m; i+=2)
			if(ans[i/2]^edge[i].c)
				printf("%d %d %d\n",edge[i].a,edge[i].v,edge[i].c^1);
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值