• CF-507E


    CF-507E


    题目大意

    就是给出一张图,每条边有一个开放情况,0表示关闭,1表示打开。现在有一个人在1号点,要去(n)号点。特别的,这个人要走最短路(无论路是否开放)。他可以用1的花费打开一条路,也可以用1的花费关闭1条路。他希望除了自己走的最短路之外的路全部关闭,自己走的最短路全部开放,求这个人可能的最小花费。并且输出做出改变的路的更改后的开放情况。

    题目分析

    不管三七二十一可以先把所有的最短路跑出来,因为边的权值都是1,所以两遍广搜就能完事。

    对于之后的操作,容易想到带着那个0和1的权值,重建一个有向图,跑一遍spfa最长路就可以出解。至于输出方案,可以使用跑完最长路之后的dis数组,暴力的使用搜索,检查每一条路径是否能符合要求。要注意的是,如果从u访问一个点v时,之前权值和大于等于u的点向v访问都无法成功的话,u也无法成功,可以减去很多搜索量。

    代码

    #include <bits/stdc++.h>
    const int MAXN=1e5+7;
    using namespace std;
    int num,head[MAXN],Head[MAXN],dep[MAXN],b[MAXN],n,m,s,t,numm,dis[MAXN],to[MAXN],change[MAXN],flag;
    struct E{
    	int u,v,w;
    }e[MAXN<<1];
    struct po{
    	int nxt,to,dis,num;
    }edge[MAXN<<1],Edge[MAXN<<1];
    inline void add_edge(int from,int to,int dis)
    {
    	edge[++num].nxt=head[from];
    	edge[num].to=to;
    	edge[num].dis=dis;
    	head[from]=num;
    }
    inline void Add_edge(int from,int to,int dis)
    {
    	Edge[++numm].nxt=Head[from];
    	Edge[numm].to=to;
    	Edge[numm].dis=dis;
    	Head[from]=numm;
    }
    inline void bfs1(){
    	memset(dep,0,sizeof(dep));
    	queue<int> q;
    	q.push(s);
    	dep[s]=1;
    	while(!q.empty()){
    		int u=q.front();q.pop();
    		for(int i=Head[u];i;i=Edge[i].nxt){
    			int v=Edge[i].to;
    			if(dep[v]) continue;
    			dep[v]=dep[u]+1;
    			if(v==t) return;
    			q.push(v); 
    		}
    	}
    }
    inline void bfs2()
    {
    	queue<int> q;
    	q.push(t);
    	b[t]=1;
    	while(!q.empty()){
    		int u=q.front(); q.pop();
    		for(int i=Head[u];i;i=Edge[i].nxt){
    			int v=Edge[i].to;
    			if(dep[v]==dep[u]-1){
    				change[i]=0;
    				add_edge(v,u,Edge[i].dis);
    				edge[num].num=(i+1)/2;
    				if(!b[v]) {
    					b[v]=1;
    					q.push(v);
    				}
    			}
    		}
    	}
    }
    inline void spfa()
    {
    	memset(b,0,sizeof(b));
    	memset(dis,-1,sizeof(dis));
    	queue<int> q;
    	q.push(s);dis[s]=0;
    	while(!q.empty()){
    		int u=q.front();q.pop();b[u]=0;
    		for(int i=head[u];i;i=edge[i].nxt){
    			int v=edge[i].to;
    			if(dis[v]<dis[u]+edge[i].dis){
    				dis[v]=dis[u]+edge[i].dis;
    				if(!b[v]){
    					b[v]=1;
    					q.push(v);
    				}
    			}
    		}
    	}
    }
    inline void dfs(int u,int l)
    {
    	if(flag==1) return;
    	if(l==dis[t]&&u==t){
    		flag=1;
    		return;
    	}
    	for(int i=head[u];i;i=edge[i].nxt){
    		int v=edge[i].to;
    		if(l+edge[i].dis<=to[v]) continue;
    		to[v]=l+edge[i].dis;
    		change[edge[i].num]=1;
    		dfs(v,to[v]);
    		if(flag==1) return;
    		change[edge[i].num]=0;
    	}
    }
    int main()
    {
    	cin>>n>>m;
    	s=1;t=n;
    	for(int i=1;i<=m;i++){
    		change[i]=2;
    		cin>>e[i].u>>e[i].v>>e[i].w;
    		int u,v,w;
    		u=e[i].u;v=e[i].v;w=e[i].w;
    		Add_edge(u,v,w);Add_edge(v,u,w);
    	}
    	bfs1();bfs2();
    	spfa();
    	memset(to,-1,sizeof(to));
    	dfs(s,0);
    	int ans=0;
    	for(int i=1;i<=m;i++){
    		if(change[i]!=1&&e[i].w==1){
    		ans++;
    		}
    		if(change[i]==1&&e[i].w==0){
    			ans++;
    		}
    	}
    	printf("%d
    ",ans);
    	for(int i=1;i<=m;i++){
    		if(change[i]!=1&&e[i].w==1){
    			printf("%d %d 0
    ",e[i].u,e[i].v);
    		}
    		if(change[i]==1&&e[i].w==0){
    			printf("%d %d 1
    ",e[i].u,e[i].v);
    		}
    	}
    	return 0;
    } 
    
  • 相关阅读:
    [USACO07DEC]观光奶牛Sightseeing Cows
    洛谷 U3348 A2-回文数
    LOJ #2037. 「SHOI2015」脑洞治疗仪
    1441 士兵的数字游戏
    BZOJ 1108: [POI2007]天然气管道Gaz
    P3047 [USACO12FEB]附近的牛Nearby Cows
    POJ 3061 Subsequence
    Hdu 5776 sum
    1052 最大M子段和
    1288 埃及分数
  • 原文地址:https://www.cnblogs.com/victorique/p/14015634.html
Copyright © 2020-2023  润新知