题目
http://codeforces.com/contest/507/problem/E
https://www.luogu.org/problemnew/show/CF507E
题目大意

solution
- 首先我们令最短路长度为d,在最短路上的损坏的边为b,所有边中未损坏的为f
- 那么我们就是要求 b + f − ( d − b ) b+f-(d-b) b+f−(d−b)等价于 2 b + f − d 2b+f-d 2b+f−d最小
- 我们知道d是不变的,f是不变的,我们只能让b尽可能小
- 所以,我们再求最短路时只要在顺便维护一下b也尽可能小就行,相当于dis为第一关键字,b为第二关键字
- 最后考虑如何输出边的改动,我们记录一下到每个点的最短路是由那个点转移过来的,并且记录一下边是哪一条
重点
- 边表一定要从0开始,这样 (0,1)是一组,标记删边时直接i和i^1即可
- 边表从0开始面,对应的head就要全赋-1
code
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cmath>
#include<cstdlib>
#include<ctime>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
inline int read(){
char ch=' ';int f=1;int x=0;
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=1e5+100;
const int M=2e5+100;
struct node
{
int v,nxt;
int w;//0坏 1没坏
int in;
}edge[M];
int head[N],cnt;
void add(int u,int v,int w)
{
cnt;
edge[cnt].v=v;
edge[cnt].w=w;
edge[cnt].in=0;
edge[cnt].nxt=head[u];
head[u]=cnt++;
}
int dis[N];int rep[N];bool vis[N];
int pre[N];int e[N];
int n;
void spfa()
{
queue <int> q;
memset(dis,inf,sizeof(dis));
memset(rep,inf,sizeof(rep));
memset(vis,0,sizeof(vis));
dis[1]=0;rep[1]=0;
vis[1]=true;pre[1]=1;
q.push(1);
while(!q.empty())
{
int u=q.front();q.pop();
vis[u]=false;
if(u==n) return ;
for(int i=head[u];i!=-1;i=edge[i].nxt)
{
int v=edge[i].v;
int w=edge[i].w^1;
if(dis[u]+1<dis[v]||(dis[u]+1==dis[v]&&rep[u]+w<rep[v]))
{
dis[v]=dis[u]+1;
rep[v]=rep[u]+w;
pre[v]=u;
e[v]=i;
if(!vis[v])
{
q.push(v);
vis[v]=true;
}
}
}
}
}
void bfs()
{
queue <int> q;
memset(vis,0,sizeof(vis));
vis[1]=true;
q.push(1);
while(!q.empty())
{
int u=q.front();q.pop();
vis[u]=false;
for(int i=head[u];i!=-1;i=edge[i].nxt)
{
if(edge[i].in==-1) continue;
int v=edge[i].v;
if(edge[i].in&&!edge[i].w)
{
printf("%d %d 1\n",u,v);
}
else if(!edge[i].in&&edge[i].w)
{
printf("%d %d 0\n",u,v);
}
edge[i].in=edge[i^1].in=-1;
if(!vis[v])
{
q.push(v);
vis[v]=true;
}
}
}
}
int main()
{
memset(head,-1,sizeof(head));
int m;
n=read();m=read();
int i,j;
int tot=0;
for(i=1;i<=m;i++)
{
int u=read(),v=read(),w=read();
add(u,v,w);
add(v,u,w);
if(w) tot++;
}
spfa();
for(int u=n;u!=pre[u];u=pre[u])
{
edge[e[u]].in=1;
edge[e[u]^1].in=1;
}
//cout<<dis[n]<<endl;
printf("%d\n",tot-dis[n]+2*rep[n]);
bfs();
return 0;
}
该博客主要解析了CF507E问题,涉及双关键字最短路的优化策略。作者指出,目标是最小化损坏边(b)加上未损坏边(f)减去最短路(d-b),通过维护最小的b来达到目的。解决方案中强调了边表从0开始的重要性,并在求最短路的同时维护b。文章还提示在记录边的改动时,要跟踪路径来源和具体边信息。
5065

被折叠的 条评论
为什么被折叠?



