1. 程式人生 > >CF507E_雙關鍵字最短路

CF507E_雙關鍵字最短路

題目

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

題目大意

在這裡插入圖片描述

solution

  1. 首先我們令最短路長度為d,在最短路上的損壞的邊為b,所有邊中未損壞的為f
  2. 那麼我們就是要求 b + f
    ( d b ) b+f-(d-b)
    等價於 2
    b + f d 2b+f-d
    最小
  3. 我們知道d是不變的,f是不變的,我們只能讓b儘可能小
  4. 所以,我們再求最短路時只要在順便維護一下b也儘可能小就行,相當於dis為第一關鍵字,b為第二關鍵字
  5. 最後考慮如何輸出邊的改動,我們記錄一下到每個點的最短路是由那個點轉移過來的,並且記錄一下邊是哪一條

重點

  1. 邊表一定要從0開始,這樣 (0,1)是一組,標記刪邊時直接i和i^1即可
  2. 邊表從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;
}