• TMOOC-1709-小明复仇


    题目描述

    小明所在的世界上一共有n个城市,城市间有m条双向道路。小明现在在城市1,他想到位于城市n的小韩隆家询问他为什么没有将自己的五三复原完成。由于小韩隆手下有许多小弟,小明担心自己可能再也回不来,所以他要先到达k个城市(编号为2到k+1)叫上自己的小弟,再到小韩隆家 。一 个城市有且只有一个小弟。但是有的小弟也曾被小明嘲讽过,不愿为小明卖命,所以小明需要先叫上其他的某些小弟才能叫到这个小弟。小明想要尽早的叫上所有k个小弟向小韩隆复仇,但是智力所限,他无法算出他找完k个小弟之后到小韩隆家的最少时间。于是他找到了你,想让你帮他算算。

    输入格式

    第一行为三个整数n、m、k,分别表示城市的数量、双向道路的数量和小弟的数量。接下来的m行每行三个整数u、V、I,表示一条路的两个端点和通过所需的时间。第m+2行为一个整数q,表示小弟有q个依赖关系。接下来q行每行两个整数x、y,表示要叫位于城市y的小弟必须先叫位于城市x的小弟。注意:由于小明十分受人厌恶,一个小弟可能依赖于不止一个小弟。经过一个城市不一定要立刻叫上该城市的小弟。

    输出格式

    一个整数,表示小明叫上所有k个小弟后到达小韩隆家的最短时间。

    输入样例

    5 7 3
    1 2 3
    2 3 4
    3 1 2
    1 4 3
    4 5 5
    2 5 3
    5 3 2
    1
    2 4 
    

    输出样例

    16
    

    其他说明

    【样例解释】小明行走的路线1->2->1->4->1->3->5。

    对于20%的数据:n<=10,k<=2。

    对于40%的数据:n<=1000,k<=10。

    对于另外30%的数据,小明觉得小韩隆太鶸,不屑叫小弟。

    对于100%的数据:1<= n<=20000,1<=m<=200000,0<=k<=20,0<=q<=100000,保证没有重边和自环、城市间两两连通、答案在 int 范围中。

    思路

    n、m很大,都跑一遍最短路会炸。参考到k很小,我们可以想到:其实最多也只是跑21个单源最短路,因为剩下的点和这道题没有直接关系。
    依照样例数据建立的图
    首先我们要确定的是,必须从起点(1)出发,带上每个小弟(k个),到达终点(n),才能算作成功。至少需要经过k+2个点。
    那么,我们要做的就是安排这个顺序,起点和终点不能动,只能安排中间k个小弟的顺序。
    在保证都能叫到小弟的情况下,可能会有多种走的方式,所以不能用拓扑排序,例如题解有:

    • 1-2-3-4-5...ans=17
    • 1-2-4-3-5...ans=16
    • 1-3-2-4-5...ans=17

    所以,只要全排列中间几个小弟,检测是否合理,两两查找相邻最短路即可,我怕数据不过,用记忆化记一下。

    大致流程

    1. 数据比较大,只能用邻接表存图;存小弟的关系用vector来存,省时省力。
    2. 接下来列出1、2...k、k+1、n的全排列(一共k+2个数,不要搞错,懒,直接用next_permutation)。
    3. 对每一种排列判断,一开始觉得是不是要像并查集那样查(就是把它所有长辈都查一遍,是不是在他前面),后来发现只用查父亲就可以了,因为有父亲的时候一定也查过了父亲的父亲,以此类推。从头查,到了一个数标记,如果他父亲没出现在前面就return。
    4. 找所有两两相邻的(全排列中)点的最短时间,他们的和与ans比,取小的即可。
    5. 输出ans即为答案。

    参考代码

    #include<iostream>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<vector>
    using namespace std;
    const int inf = 0x3f3f3f3f,maxm=400002,maxn=20001;
    struct Edge{
    	int next,to,dis;//标准建边结构体 
    }e[maxm];
    vector<int> f[maxn];//接i小弟的时候必须有f[i]小弟 
    //book和vis是表示访问状态、cnt全排列用、 dis[i][j]表示从i~j的最短时间 
    int n,m,k,q,x,y,u,s,v,w,i,j,r,minn,numE=0,ans=inf;
    int book[maxn],vis[maxn],head[maxm],dis[25][maxn],cnt[21];
    struct cmp{
    	//优先队列出队顺序从小打大 
    	bool operator()(int x,int y){
    		return dis[s][x]>dis[s][y];
    	}
    };
    //建边函数,将同一个出发点的边给集合起来。
    void addEdge(int from,int to,int dis){ 
    	e[++numE].next=head[from];
    	e[numE].to=to;
    	e[numE].dis=dis;
    	head[from]=numE;
    }
    bool check(){//能否接到全部k个小弟
    	memset(book,0,sizeof(book));//清空数组 
    	for(i=1;i<k+1;i++){//起点终点不用查 
    		book[cnt[i]]=1;//先标记 
    		for(j=0;j<f[cnt[i]].size();j++)
    			//如果他的大哥没来,他也不能走 
    			if(!book[f[cnt[i]][j]])return false;
    	}
    	return true;
    }
    void dijkstra(int x){//dijkstra+优先队列优化 
    	s=x; 
    	memset(vis,0,sizeof(vis));//清空数组 
    	priority_queue<int,vector<int>,cmp> q; 
    	dis[s][s]=0;q.push(s);
    	while(!q.empty()){
    		int u=q.top();q.pop();//找出时间最小的来松弛 
    		if(vis[u])continue;
    		vis[u]=1;
    		for(j=head[u];j;j=e[j].next){//和他相邻的边s 
    			int v=e[j].to;
    			dis[s][v]=min(dis[s][v],dis[s][u]+e[j].dis);//松弛 
    			q.push(v);//继续松弛 
    		}
    	}
    }
    void find(int u,int v,int l){
    	//最后一项不能交换
    	if(l!=k&&dis[v][u]!=inf)dis[u][v]=dis[v][u];
    	else dijkstra(u);
    }
    int main(){
    	memset(dis,0x3f3f3f3f,sizeof(dis));
    	cin >> n >> m >> k;
    	for(i=1;i<=n;i++)vis[i]=0;
    	for(i=1;i<=k+1;i++)cnt[i-1]=i;//全排列 
    	cnt[k+1]=n;//全排列用 
    	for(i=0;i<m;i++){
    		cin >> u >> v >> w;
    		addEdge(u,v,w);addEdge(v,u,w);//建边 
    	}
    	cin >> q;
    	for(i=0;i<q;i++){
    		cin >> x >> y;
    		f[y].push_back(x);//要注意可以多个大哥 
    	}
    	do{
    		if(!check())continue;//如果顺序错的就跳过 
    		int p=0;
    		for(i=0;i<k+1;i++){//找每两个相邻最短时间; 
    			if(dis[cnt[i]][cnt[i+1]]==inf)
    				find(cnt[i],cnt[i+1],i);
    			p+=dis[cnt[i]][cnt[i+1]];
    			
    		}
    		ans=min(ans,p);//是不是最短时间? 
    	}while(next_permutation(cnt+1,cnt+k+1)); //全排列 
    	cout << ans;
    	return 0;
    }
    
  • 相关阅读:
    Tomcat 7 自动加载类及检测文件变动原理
    ElasticSearch查询
    ElasticSearch集群的基本原理
    ElasticSearch基础
    hbase时间不同步问题引起的bug
    IDEA运行异常java.lang.NoClassDefFoundError: org/apache/spark/api/java/function/Function
    spark任务提交之SparkLauncher
    spark调优(二)-Apache Spark 内存管理详解
    spark调优(一)-开发调优,数据倾斜,shuffle调优
    spark内核源码深度剖析(1)--Spark内核架构深度剖析
  • 原文地址:https://www.cnblogs.com/dmoransky/p/10742616.html
Copyright © 2020-2023  润新知