【最短路】CF449B Jzzhu and Cities

【题目描述】

CF449B Jzzhu and Cities

【分析】

  • 题意:n个点,m条带权边的无向图,其中有k条特殊边连接1和i
  • 问最多能删除多少条特殊边,能使每个点到1的最短距离不变
  • 解答:直接在原图上跑最短路,得到dis[x]表示x到1的最短路。
  • 对于每个用特殊边k连接的点i,如果dis[x]<w[k],那么k可以被删除
  • 如果dis[x]=w[k],看x的其他出边如果也在最短路上,那么k也可以被删除
  • 如此看来,原题就是一个裸的最短路

【代码】


#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> TQX;
const int N=1e6+10;
int n,m,k,first[N],cnt,val[N],ans,vis[N],dis[N],d[N],where[N],tot[N];
struct node{
	int u,v,w,nxt;
}e[N];
void add(int u,int v,int w){
	e[++cnt].u=u;e[cnt].v=v;e[cnt].w=w;
	e[cnt].nxt=first[u];first[u]=cnt;
}
void dijkstra(int s){
	memset(vis,0,sizeof(vis));
	memset(dis,0x3f,sizeof(dis));
	dis[s]=0;
	priority_queue<TQX,vector<TQX>,greater<TQX> >q;
	q.push(make_pair(dis[s],s));
	while(!q.empty()){
		TQX t=q.top();q.pop();
		int d=t.first,u=t.second;
		if(vis[u]) continue;
		vis[u]=1;
		for(int i=first[u];i;i=e[i].nxt){
			int v=e[i].v;
			if(d+e[i].w==dis[v]) tot[v]++;
			if(d+e[i].w<dis[v]){
				tot[v]=1;
				dis[v]=d+e[i].w;
				q.push(make_pair(dis[v],v));
			}
		}
	} 
}//dijkstra模板
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9'){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*f;
}
int main(){
	n=read();m=read();k=read();
	for(int i=1;i<=m;i++){
		int u=read(),v=read(),w=read();
		add(u,v,w);
		add(v,u,w);
	
	memset(val,-1,sizeof(val));
	for(int i=1;i<=k;i++){
		int v=read(),w=read();
		add(1,v,w);
		d[cnt]=1;
		val[i]=w;
		where[i]=v;
		add(v,1,w);
		d[cnt]=1;
	}
	dijkstra(1);
	for(int i=1;i<=k;i++){
		int t=where[i],w=val[i];
		if(dis[t]<w) ans++;//有更短的路径:可以删除
		if(dis[t]==w){
			if(tot[t]>1){
				ans++;
				tot[t]--;
			}//有别的最短路:可以删除
		} 
	}
	cout<<ans;
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值