Jzzhu and Cities
题目链接
题意:
n个点,m条带权边的无向图,另外还有k条特殊边,每条边连接1和i。问最多可以删除这k条边中的多少条,使得每个点到1的最短距离不变。
思路:
显然先跑一遍最短路,分别记录首都到各个城市的最短路径的条数,随后遍历k条特殊边,考虑这条边连向的城市,如果首都到该城市的最短路小于该火车线路的距离,显然该线路可以删去,大于的情况不可能存在,最后考虑等于的情况,如果首都到该城市的最短路径数大于1,说明可以删去不影响,同时首都到该城市的最短路径数减一。具体实现见代码。
点击查看代码
#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define ll long long
const ll N = 1e6+5;
ll n,m,k;
ll M=1000000;
//存图
struct edge{
ll next,vi,wi;
edge(){}
edge(ll _next,ll _vi,ll _wi){
next=_next,vi=_vi,wi=_wi;
}
}e[N];
ll head[N/10+10],index1;
void insert(ll a,ll b,ll c){
e[index1]=edge(head[a],b,c);
head[a]=index1++;
}
ll arr[N];
ll brr[N];
ll js[N];
ll dis[N];
bool vis[N];
multiset<pair<ll,ll>>s;
//跑最短路径和路径最短路径数
void hanshu(ll u){
for(ll i=1;i<=n;++i){
dis[i]=0x7fffffffffffffff;
}
dis[u]=0;
s.insert({0,u});
js[u]=1;
while(!s.empty()){
ll dingdian=s.begin()->second;
s.erase(s.begin());
if(vis[dingdian]) continue;
vis[dingdian]=1;
for(ll j=head[dingdian];~j;j=e[j].next){
ll v=e[j].vi;
ll w=e[j].wi;
if(dis[v]>dis[dingdian]+w){
dis[v]=dis[dingdian]+w;
js[v]=js[dingdian];
s.insert({dis[v],v});
}else if(dis[v]==dis[dingdian]+w){
js[v]+=js[dingdian];
js[v]=min(js[v],M); //最短路条数会爆long long,给它限定一个不爆long long且不影响答案的数字即可
}
}
}
}
void solve(){
//初始化、读取及插边操作
memset(head,-1,sizeof(head));
cin>>n>>m>>k;
for(ll i=1;i<=m;++i){
ll a,b,c;
cin>>a>>b>>c;
insert(a,b,c);
insert(b,a,c);
}
for(ll i=1;i<=k;++i){
ll a=1;
cin>>arr[i]>>brr[i];
insert(a,arr[i],brr[i]);
insert(arr[i],a,brr[i]);
}
hanshu(1);
ll ans=0;
//开始遍历k条特殊路径并判断是否删边
for(ll i=1;i<=k;++i){
ll w=brr[i];
ll v=arr[i];
if(dis[v]<w){
ans++;
}else if(dis[v]==w){
if(js[v]>1){
ans++;
js[v]--;
}
}
}
cout<<ans<<endl; //输出答案
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
ll _=1;
// cin>>_;
while(_--)
solve();
return 0;
}

浙公网安备 33010602011771号