CF507E_雙關鍵字最短路
阿新 • • 發佈:2018-11-08
題目
http://codeforces.com/contest/507/problem/E
https://www.luogu.org/problemnew/show/CF507E
題目大意
solution
- 首先我們令最短路長度為d,在最短路上的損壞的邊為b,所有邊中未損壞的為f
- 那麼我們就是要求 等價於 最小
- 我們知道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;
}