zoukankan      html  css  js  c++  java
  • 图论小测

    写在前面

    (caq,szt)不在,速来(rank1),图论那一部分倒是都没学完,反倒是没考,我就(Tarjan)写的博客好 ,(出了Tarjan就睡觉吧),要是早看一下(szt)博客,就(260)了,真的是,害

    期望得分 : 200 ,实际得分160

    (T1 transprt)

    【题目描述】:

    给定(n)个点,(m)条双向边,(k)条行驶路线,边有边权(w),行驶路线有特定费用(m),给定点(s),输出(s)到其他点的最短路径长度,数据保证图是连通的。

    【输入格式】:

    输入的第(1)行:(n,m,k,s),见描述
    接下来有(m)行: 每行(3)个整数,(x_i,y_i,w_i),表示第(i)条道路连接(x_i)(y_i)路口,权值为(w_i)
    接下来有(k)行:每行首先(2)个整数,(b_i,t_i),表示(i)路公交车费用为(b_i),,并且停靠(t_i)个站点,之后输入(t_i)个站点

    【输出格式】

    (n)个整数,表示(s)点到各点的最短路

    【样例】:

    【输入】:
    5 4 1 1
    1 2 1
    2 3 1
    3 4 1
    4 5 1
    2 4 2 3 4 5
    【输出】:
    0 1 2 3 3

    【数据范围】:

    (1 leq nleq 10^6 , 1leq m leq 2 imes 10^6 , 1leq k leq 10^5 , sum t_i leq 2 imes 10^6 , 1 leq k_i , b_i leq 10^9)

    (solution)

    首先,如果有点脑子的话,当(k=0)时,相当于就跑一个最短路,那么你就可以得到(30opts)
    其次,我们有一个(({sum t_i} ^2))的暴力,然后就可以得到(60opts),做法就是跑一个最短路,在最短路的时候,首先进行一下判断是否需要换车,然后正常跑一个最短路就行了,

    最后,我们发现数据过分地大了,显然(({sum t_i} ^2))的暴力是过不了,当然这个(({sum t_i} ^2))只是建的边数,考虑缩小建的边数,做法:对公交车建一个点,路线上的每一个点连向这个新建的点,边权为(b_i),新建的点也连向路线上的每一个点,边权为(0),然后图的边数为(n+sum t_i),可过

    数据点下载

    (Code)】:

    考场(60)代码:

    /*
     by : Zmonarch
     分类拿分, 
     每一条路线只一次更优,外层枚举路线,内层搞一下 
     在DIJ的板子上加了一个更新路线的操作, 
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <vector>
    #define int long long
    using namespace std ;
    const int kmaxn = 2e6 + 10 ;
    inline int read()
    {
    	int x = 0 , f = 1 ; char ch = getchar() ;
    	while(!isdigit(ch)) { if(ch == '-') f = - 1 ; ch = getchar() ; }
    	while( isdigit(ch)) { x = x * 10 + ch - '0' ; ch = getchar() ; }
    	return x * f ;
    }
    int n , m , k , s ;
    struct node 
    {
    	int nxt , u , v , val ;
    }e[kmaxn << 1] ;
    int tot , h[kmaxn << 1] ;
    vector<int> stop[kmaxn] , point[kmaxn]; //公交车在哪一个站点可以上车
    int cost[kmaxn] ; //哪一路公交车上车的费用 
    bool used[kmaxn] ;  //哪一路公交车是否使用过了 
    void add(int u , int v , int val)
    {
    	e[++tot].nxt = h[u] ;
    	e[tot].u = u ;  
    	e[tot].v = v ;
    	e[tot].val = val ;
    	h[u] = tot ;
    } 
    priority_queue<pair<int , int > > q ;
    int dis[kmaxn << 1] ;
    bool vis[kmaxn << 1] ;
    void dij0(int s)//没有负边,就跑dij ,30分应该是稳了 
    {
    	memset(dis , 63 , sizeof(dis)) ;
    	memset(vis , 0 , sizeof(vis)) ;
    	q.push(make_pair(0 , s)) ;
    	dis[s] = 0 ; 
    	while(!q.empty())
    	{
    		int u = q.top().second ; 
    		q.pop() ;
    		if(vis[u]) continue ;
    		vis[u] = 1 ;
    		for(int i = h[u] ; i ; i = e[i].nxt)
    		{
    			int  v = e[i].v ;
    			if(dis[v] > dis[u] + e[i].val)
    			{
    				dis[v] = dis[u] + e[i].val ;
    				q.push(make_pair(-dis[v] ,v)) ; 
    			}
    		}
    	}
    }
    void dij1(int s)
    {
    	memset(dis , 63 , sizeof(dis)) ; 
    	memset(vis , 0 , sizeof(vis)) ;
    	dis[s] = 0 ; 
    	q.push(make_pair(-dis[s] , s)) ;
    	while(!q.empty())
    	{
    	//	printf("test : -------------- u , dis %lld , %lld
    " , u , dis[u]) ;
    		int u = q.top().second ;
    		q.pop() ;
    		if(vis[u]) continue ;
    		vis[u] = 1 ; 
    		
    		for(int i = 0 ; i < point[u].size() ; i++) //枚举出每一个条经过该点公交路线
    		{
    			int road = point[u][i] ; 
    			used[road] = true ; //这条路线已经走过了,如果还要走这条路线回到一个点,还不如直接从这个直接做到那
    			for(int j = 0 ; j < stop[road].size() ; j++) //更新一下他下一次能走的点
    			{
    				int v = stop[road][j] ; // 该路线的下一个节点 
    				if(dis[v] > dis[u] + cost[road]) // 更新路线 
    				{
    					dis[v] = dis[u] + cost[road] ;
    					if(!vis[v]) 
    					{
    						q.push(make_pair(-dis[v] , v) ) ;
    					}
    				}
    			} 
    		}
    		//路线走完了,就走正常的路了 
    		for(int i = h[u] ; i ; i = e[i].nxt) 
    		{
    			int v = e[i].v ; 
    			if(dis[v] > dis[u] + e[i].val) 
    			{
    				dis[v] = dis[u] + e[i].val ; 
    				if(!vis[v]) 
    				{
    				q.push(make_pair(-dis[v] , v)) ;		
    				} 
    			}
    		}	
    	}
    }
    signed main()
    {
    	freopen("transprt.in" , "r" , stdin) ; 
    	freopen("transprt.out" , "w" , stdout) ;
    	n = read() , m = read() , k = read() , s = read() ; 
    	for(int i = 1 ; i <= m ; i++)
    	{
    		int u = read() , v = read() , w = read() ;
    		add(u , v , w) ; 
    		add(v , u , w) ; 
    	}
    	if(k == 0) //城市中没有其他的路线,就是每一个到每一个点的最短路
    	{
    		dij0(s) ;
    		for(int i = 1 ; i <= n ; i++)
    		{
    			printf("%lld " , dis[i]) ;
    		}
    		return 0 ; 
    	} 
    	if(k != 0 )   
    	{
    		for(int i = 1 ; i <= k ; i++)
    		{
    			cost[i] = read() ;
    			int sum = read() ; 
    			//printf("test : sum----%lld
    " , sum) ;
    			for(int j = 1 ; j <= sum ; j++)
    			{
    				int v = read() ; 
    			//	printf("%lld %lld
    " , v , j ) ;
    				stop[i].push_back(v) ; //存下站点 
    				point[v].push_back(i) ; //存下每一个节点会有多少条路线经过 
    			}
    		}
    		dij1(s) ;
    		for(int i = 1 ; i <= n ;i++) 
    		{
    			printf("%lld " , dis[i]) ;
    		}
    	}
    	return 0 ;
    }
    

    满分代码:

    
    

    (T2 irrigate)

    (loj)新的开始同题,建个超级源点一眼秒

    /* 
     by : Zmonarch
     知识点 : 最小生成树 
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #define int long long
    using namespace std ;
    const int kmaxn = 2e6 + 10 ; 
    inline int read()
    {
    	int x = 0 , f = 1 ; char ch = getchar() ;
    	while(!isdigit(ch)) { if(ch == '-') f = - 1 ; ch = getchar() ; }
    	while( isdigit(ch)) { x = x * 10 + ch - '0' ; ch = getchar() ; }
    	return x * f ;
    }
    struct node 
    {
    	int nxt , v , u , val ;
    }e[kmaxn << 1] ; 
    int fa[kmaxn << 1] ; 
    int ans = 0 , n , m ;
    int a[kmaxn << 1] ;  
    int tot = 0 , cnt = 1 ; 
    void add(int u , int v , int w)
    {
    	e[++tot].u = u ; 
    	e[tot].v = v ; 
    	e[tot].val = w ; 
    }
    bool cmp(node x , node y) 
    {
    	return x.val < y.val ;
    } 
    int findx(int x) 
    {
    	if(x == fa[x]) return x ; 
    	else return fa[x] = findx(fa[x]) ; 
    }
    void kruscal()
    {
    	sort(e + 1 , e + tot + 1 , cmp) ;
    	for(int i = 1 ; i <= n ; i++)
    	{
    		fa[i] = i ; 
    	}
    	for(int i = 1 ; i <= tot ; i++)
    	{
    		int fu = findx(e[i].u ) ; 
    		int fv = findx(e[i].v ) ; 
    		if(fu != fv) 
    		{
    			fa[fu] = e[i].v ; 
    			cnt ++ ; 
    			ans += e[i].val ; 
    			if(cnt == n + 1 ) return ; //这里加上超级源点是五个点
    		}
    	}
    }
    signed main()
    {
    	freopen("irrigate.in" , "r" , stdin) ; 
    	freopen("irrigate.out" , "w" , stdout) ; 
    	n = read() ; 
    	for(int i = 1 ; i <= n ; i++) 
    	{
    		a[i] = read() ;
    	}
    	for(int i = 1 ; i <= n ; i++)
    	{
    		for(int j = 1 ; j <= n ; j++)
    		{
    			int w = read() ; 
    			if(i == j) continue ;//屏蔽掉自环 
    			add(i , j , w) ;
    		}
    	}
    	for(int i = 1 ; i <= n ; i++)  //建立一个超级源点就可以解决掉在不在一个点取水了 
    	{
    		add(0 , i , a[i]) ;  
    	}
    	kruscal() ; 
    	printf("%lld" , ans) ; 
    	return 0 ;
    	
    }
    

    (T3 duel)

    【题目描述】:

    给定(n)个局面,(m)个转移,求解(n)个状态是先手必胜状态还是先手必败状态,先手必胜输出(First),先手必败输出(Last)

    【输入输出】:

    如题面所说

    【数据范围】:

    (1leq n leq 10^6 , 1 leq m leq 2 imes 10^6)

    (Solution)

    显然,博弈论加拓扑,显然,局面的转移是一个(DAG),然后有几个显然的结论
    (1.)先手获胜局面为先手必胜态
    (2.)先手落败局面为先手必败态
    (3.)当前有一个局面为先手必败态的后继局面,那么当前局面必然为先手必胜态的前继局面,为先手必胜态
    (4.)当前有一个局面为先手必胜态的后继局面,那么当前局面必然为先手必败态额前继局面,应也为先手必败态

    同样的,我们发现,入度为(0),也就是没有任何给予这一个局面转移,(so),该局面为初始局面
    出度为(0),也就是不会给予任何局面的转移,(so)该局面为结束状态

    同样的,既然是(DAG),那就拓扑序转移即可

    参考(szt)大佬

    (std : : Code)

    /*
     by : Zmonarch 
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <stdlib.h>
    #include <time.h>
    #define int long long
    const int kmaxn = 1e6 ;
    using namespace std ;
    inline int read()
    {
    	int x = 0 , f = 1 ; char ch = getchar() ;
    	while(!isdigit(ch)) { if(ch == '-') f = - 1 ; ch = getchar() ; }
    	while( isdigit(ch)) { x = x * 10 + ch - '0' ; ch = getchar() ; }
    	return x * f ;
    }
    int n , m ;
    struct node 
    {
    	int nxt , v , u , val ;
    }e[kmaxn << 1] ; 
    int inv[kmaxn] , ino[kmaxn] ; 
    bool ans[kmaxn] ;
    int tot , h[kmaxn << 1] ;
    void add(int u , int v )
    {
    	e[++tot].nxt = h[u] ;
    	e[tot].u = u ;
    	e[tot].v = v ;
    	h[u] = tot ;
    } 
    int ans1[kmaxn << 1] ; 
    int ans2[kmaxn << 1] ;
    queue<int> q ;
    void topo()
    {
    	for(int i = 1 ; i <= n ; i++)
    	{
    		if(inv[i] == 0) 
    		{
    			int x = read() ;
    			q.push(i) ;
    			if(x) ans1[i] = 1 , ans2[i] = 0 ; //先手必赢态
    			else ans1[i] = 0 , ans2[i] = 1 ;  
    		}
    		else ans1[i] = 0 , ans2[i] = 2147483647 ; 
    	}
    	while(!q.empty())
    	{
    		int u = q.front() ; 
    		q.pop() ;
    		for(int i = h[u] ; i ; i = e[i].nxt) 
    		{
    			int v = e[i].v ; 
    			ans1[v] = max(ans1[v] , ans2[u]) ;
    			ans2[v] = min(ans2[v] , ans1[u]) ; 
    			inv[v] -- ;
    			if(inv[v] == 0) q.push(v) ;
    		}	
    	}
    }
    signed main()
    {
    	//freopen("duel.in" ,"r" , stdin) ; 
    	//freopen("duel.out","w",stdout) ;
    	 n = read() , m = read() ; 
    	for(int i = 1 ; i <= m ; i++)
    	{
    		int u = read() , v = read() ; 
    		add(v , u) ;
    		inv[u] ++ ;
    	}
    	topo() ; 
    	for(int i = 1 ; i <= n ; i++) 
    	{
    		if(ans1[i]) printf("First
    ") ;//该局面如果是先手必胜态 
    		else printf("Last
    ") ;//该局面是先手必败态 
    	} 
    	return 0 ;
    }
    
    
  • 相关阅读:
    IPFS搭建&集群
    request.getInputStream() 流只能读取一次问题
    八、网页版消息推送SDK-WebSockets
    Spring boot 打包瘦身方法
    七、Mosquito 集群搭建
    org.springframework.web.HttpMediaTypeNotSupportedException: Content type 'multipart/form-data;boundary=----WebKitFormBoundaryRAYPKeHKTYSNdzc1;charset=UTF-8' not supported
    RocketMQ Java 客户端实现
    RocketMQ 单机安装
    Vue.js面试题整理(转载)
    computed和watch的使用场景
  • 原文地址:https://www.cnblogs.com/Zmonarch/p/14364191.html
Copyright © 2011-2022 走看看