zoukankan      html  css  js  c++  java
  • 【39.87%】【BZOJ 1880】[Sdoi2009]Elaxia的路线

    Time Limit: 4 Sec  Memory Limit: 64 MB
    Submit: 1041  Solved: 415
    [Submit][Status][Discuss]

    Description

    最近,Elaxia和w**的关系特别好,他们很想整天在一起,但是大学的学习太紧张了,他们 必须合理地安排两个人在一起的时间。Elaxia和w**每天都要奔波于宿舍和实验室之间,他们 希望在节约时间的前提下,一起走的时间尽可能的长。 现在已知的是Elaxia和w**所在的宿舍和实验室的编号以及学校的地图:地图上有N个路 口,M条路,经过每条路都需要一定的时间。 具体地说,就是要求无向图中,两对点间最短路的最长公共路径。

    Input

    第一行:两个整数N和M(含义如题目描述)。 第二行:四个整数x1、y1、x2、y2(1 ≤ x1 ≤ N,1 ≤ y1 ≤ N,1 ≤ x2 ≤ N,1 ≤ ≤ N),分别表示Elaxia的宿舍和实验室及w**的宿舍和实验室的标号(两对点分别 x1,y1和x2,y2)。 接下来M行:每行三个整数,u、v、l(1 ≤ u ≤ N,1 ≤ v ≤ N,1 ≤ l ≤ 10000),表 u和v之间有一条路,经过这条路所需要的时间为l。 出出出格格格式式式::: 一行,一个整数,表示每天两人在一起的时间(即最长公共路径的长度)。

    Output

    一行,一个整数,表示每天两人在一起的时间(即最长公共路径的长度)

    Sample Input

    9 10
    1 6 7 8
    1 2 1
    2 5 2
    2 3 3
    3 4 2
    3 9 5
    4 5 3
    4 6 4
    4 7 2
    5 8 1
    7 9 1

    Sample Output

    3

    HINT

    对于30%的数据,N ≤ 100;
    对于60%的数据,N ≤ 1000;
    对于100%的数据,N ≤ 1500,输入数据保证没有重边和自环。

    Source


    【题解】

    假设你已经求出了他们从宿舍到各自的实验室的最短路的重叠的边。且它们构成了一个新的图G。

    那么你接下来要怎么做?

    要公共边最长。那么就是要求一条最长链了!最长链可以用拓扑排序的方法求得。(get 新技能)

    然后解决获取重边的问题。

    可以这样。以4个点(宿舍和实验室)为起点分别做4次spfa;

    然后枚举每一条边

    如果

    spfa起点[左端点]+边权+spfa终点[右端点]

    上面这个式子等于起点到终点的最短路。

    那么这条边就在起点到终点的最短路上。

    如果这条边分别在两个人的最短路上。则加入图G。

    懂了吧。

    好厉害的方法。。

    queue容器和vector容器真的很方便。

    【代码】

    #include <cstdio>
    #include <queue>
    #include <vector>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int MAXN = 1600;
    
    int n, m,xx1,yy1,xx2,yy2,rudu[MAXN],ans = 0;
    int disxx1[MAXN], disyy1[MAXN], disxx2[MAXN], disyy2[MAXN],tt[MAXN];
    
    struct ed_ge
    {
    	int u, v, w;
    };
    
    vector <ed_ge> bian;
    vector <int> g[MAXN],G[MAXN];
    vector <int> cost[MAXN];
    queue <int> dl;
    bool inque[MAXN];
    
    void input_data()
    {
    	scanf("%d%d", &n, &m);
    	scanf("%d%d%d%d", &xx1, &yy1, &xx2, &yy2);	
    	for (int i = 1; i <= m; i++)
    	{
    		int x, y, z;
    		scanf("%d%d%d", &x, &y, &z);
    		ed_ge temp;
    		temp.u = x; temp.v = y; temp.w = z;
    		bian.push_back(temp);
    		g[x].push_back(bian.size() - 1);
    		temp.u = y; temp.v = x;
    		bian.push_back(temp);
    		g[y].push_back(bian.size() - 1);
    	}
    }
    
    void spfa(int qidian, int dis[])//memset(dis)写在这里面貌似不行。
    {
    	memset(inque, false, sizeof(inque));
    	dl.push(qidian);
    	inque[qidian] = true; dis[qidian] = 0;
    	while (!dl.empty())
    	{
    		int x = dl.front(); dl.pop();
    		inque[x] = false;
    		int len = g[x].size();
    		for (int i = 0; i <= len - 1; i++)
    		{
    			int temp =g[x][i];
    			int y = bian[temp].v,w = bian[temp].w;
    			if (dis[y] > dis[x] + w)
    			{
    				dis[y] = dis[x] + w;
    				if (!inque[y])
    				{
    					inque[y] = true;
    					dl.push(y);
    				}
    			}
    		}
    	}
    }
    
    void get_ans()
    {
    	memset(disxx1, 127 / 3, sizeof(disxx1));
    	memset(disyy1, 127 / 3, sizeof(disxx1));
    	memset(disxx2, 127 / 3, sizeof(disxx1));
    	memset(disyy2, 127 / 3, sizeof(disxx1));
    	spfa(xx1, disxx1); spfa(yy1, disyy1);//4个key点开始进行最短路
    	spfa(xx2, disxx2); spfa(yy2, disyy2);
    	int len = bian.size();
    	for (int i = 0; i <= len-1; i++)//判断这条边是不是同时在两个人的最短路上。
    	{
    		int l = bian[i].u, r = bian[i].v, w = bian[i].w;
    		int len1 = min(disxx1[l], disxx1[r]) + min(disyy1[l], disyy1[r]) + w;
    		int len2 = min(disxx2[l], disxx2[r]) + min(disyy2[l], disyy2[r]) + w;
    		if (len1 == disxx1[yy1] && len2 == disxx2[yy2])
    		{
    			if (disxx1[l] < disxx1[r])
    			{
    				G[l].push_back(r);
    				cost[l].push_back(w);
    				rudu[r]++;
    			}
    		}
    	}
    	for (int i = 1;i <= n;i++)//接下来进行拓扑排序求最长链
    		if (rudu[i] == 0)//也可以两次dfs求最长路然后获得最长链
    			dl.push(i);
    	while (!dl.empty())
    	{
    		int x = dl.front();
    		dl.pop();
    		int len = G[x].size();
    		for (int i = 0; i <= len - 1; i++)
    		{
    			int y = G[x][i],w = cost[x][i];
    			if (tt[y] < tt[x] + w)
    			{
    				tt[y] = tt[x] + w;
    				ans = max(ans, tt[y]);
    			}
    			rudu[y]--;
    			if (!rudu[y])
    				dl.push(y);
    		}
    	}
    }
    
    void output_ans()
    {
    	printf("%d
    ", ans);
    }
    
    int main()
    {
    	//freopen("F:\rush.txt", "r", stdin);
    	input_data();
    	get_ans();
    	output_ans();
    	return 0;
    }


  • 相关阅读:
    [转载]每天要说无数次的话,原来英语这么说
    [转载]What I Have Lived For 一生何求?
    WIN 7 和fedora双系统引导问题
    [转载]网站建设中一些容易被忽视的问题
    linux进程控制-wait()
    shell(2)
    电脑英语缩略词
    shell(1)
    [转载]无论成败 但求做最好的自己
    [转载]C++出错提示英汉对照表
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632225.html
Copyright © 2011-2022 走看看