zoukankan      html  css  js  c++  java
  • 那一天她离我而去 (最短路)

    (内部题目不放题面了)

    分析

    • 之前考过一道原题但是数据过水 所以暴力能过……
    • 先来说一下暴力的算法 首先对于1号节点 如果1号节点的入度为1 那么肯定无法回到1号节点 输出-1 最小环可以看成是从1号节点出发 然后经过一号节点的某一个可到达位置 再去一号节点的另一个可到达位置 然后加上这两个到1号节点的路径长 所以我们可以枚举一遍1号节点可到达的所有点 然后每次都跑一遍最短路 更新答案
    • 但是暴力显然最坏的情况会退化成O((n^2)(log_n)) 显然是过不去这个题的 我们可以考虑分组 然后跑最短路
    • 如果我们把1可以到达的一些点分为一组 另i一些点分为另外一组 然后建立超级源点向第一组的所有点都加边 权值为1到达该点的路径长 建立超级汇点向另外一组的所有点都加边 权值也为1到达该点的路径长 显然答案就是超级源点到超级汇点的最短路
    • 接下来就是我们如何不漏情况的分组 对于两个点 我们必须令其至少一次在不同的两组中 这样才可能计算它对于答案的贡献 所以可以使用二进制分组 因为对于两个节点 编号肯定不同 编号不同则编号化成二进制后 也至少有一位是不同的 所以我们可以枚举每个二进制位 然后将该位是1的分成一组 该位是0的分成一组 这样可以保证不会漏掉答案
    • 实现细节挺多的

    Code

    #include<bits/stdc++.h>
    using namespace std;
    #define rint register int
    const int maxn = 2e4 + 10;
    
    int head[maxn << 3];
    int Head[maxn << 3];
    int cnt;
    int fz[] = {1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384};
    int ans;
    int dis[maxn];
    int vis[maxn];
    
    struct node{
    	int next,to,dis;
    }a[maxn << 3];
    
    void add(int x,int y,int z){
    	a[++cnt].next = head[x];
    	a[cnt].to = y;
    	a[cnt].dis = z;
    	head[x] = cnt;
    }
    
    void init(){
    	cnt = 0;
    	ans = INT_MAX;
    	memset(head,0,sizeof(head));
    }
    
    deque<int> q;
    
    void spfa(int s){
    	memset(dis,0x3f,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	dis[s] = 0; vis[1] = 1;
    	q.push_front(s);
    	while(!q.empty()){
    		rint u = q.front(); q.pop_front();
    		vis[u] = 0;
    		for(rint i = head[u];i;i = a[i].next){
    			rint v = a[i].to;
    			if(dis[v] > dis[u] + a[i].dis){
    				dis[v] = dis[u] + a[i].dis;
    				if(!vis[v]) {
    					if(q.empty()) q.push_front(v);
    					else if(dis[v] < dis[q.front()]) q.push_front(v);
    					else q.push_back(v);
    				}
    				vis[v] = 1;
    			}
    		}
    	}
    }
    
    int main(){
    	freopen("leave.in","r",stdin);
    	freopen("leave.out","w",stdout);
    	int T;scanf("%d",&T);
    	while(T--){
    		init();
    		int n,m;scanf("%d%d",&n,&m);
    		for(rint i = 1;i <= m;++i){
    			int u,v,z;scanf("%d%d%d",&u,&v,&z);
    			add(u,v,z);add(v,u,z);
    		}
    		for(rint i = head[1];i;i = a[i].next) Head[a[i].to] = head[a[i].to];
    		rint now = cnt;
    		for(rint i = 0;n >> i;++i){
    			cnt = now;
    			for(rint j = head[1];j;j = a[j].next){
    				rint v = a[j].to;
    				if(v & (1 << i)) add(n + 1,v,a[j].dis);
    				else add(v,n + 2,a[j].dis);
    			}
    			spfa(n+1);
    			ans = min(ans,dis[n+2]);
    			for(rint j = head[1];j;j = a[j].next) head[a[j].to] = Head[a[j].to];
    			head[n + 1] = head[n + 2] = 0;
    		}
    		if(ans != 0x3f3f3f3f) cout << ans << endl;
    		else cout << "-1" << endl;
    	}
    	return 0;
    }
    
    
    如初见 与初见
  • 相关阅读:
    图片局部放大插件jquery.jQZoom.js
    FastCGI for iis6不能限制程序池的CPU
    技术普及帖:你刚才在淘宝上买了一件东西
    转载 ListView动态加载数据模板
    转载 Drawable、Bitmap、byte[]之间的转换
    转载 一个ImageView 点击时是一张图片,放开时换另一张图片
    转载 java抽象类与接口的区别
    转载 Android AsyncTask
    转载 Android实现ListView异步加载图片
    转载 Android权限大全
  • 原文地址:https://www.cnblogs.com/HISKrrr/p/13615893.html
Copyright © 2011-2022 走看看