zoukankan      html  css  js  c++  java
  • 洛谷 P1821 [USACO07FEB]银牛派对Silver Cow Party 题解

    P1821 [USACO07FEB]银牛派对Silver Cow Party

    题目描述

    One cow from each of N farms (1 ≤ N ≤ 1000) conveniently numbered 1..N is going to attend the big cow party to be held at farm #X (1 ≤ X ≤ N). A total of M (1 ≤ M ≤ 100,000) unidirectional (one-way roads connects pairs of farms; road i requires Ti (1 ≤ Ti ≤ 100) units of time to traverse.

    Each cow must walk to the party and, when the party is over, return to her farm. Each cow is lazy and thus picks an optimal route with the shortest time. A cow's return route might be different from her original route to the party since roads are one-way.

    Of all the cows, what is the longest amount of time a cow must spend walking to the party and back?

    寒假到了,N头牛都要去参加一场在编号为X(1≤X≤N)的牛的农场举行的派对(1≤N≤1000),农场之间有M(1≤M≤100000)条有向路,每条路长Ti(1≤Ti≤100)。

    每头牛参加完派对后都必须回家,无论是去参加派对还是回家,每头牛都会选择最短路径,求这N头牛的最短路径(一个来回)中最长的一条路径长度。

    输入格式

    第一行三个整数N,M, X;

    第二行到第M+1行:每行有三个整数Ai,Bi, Ti ,表示有一条从Ai农场到Bi农场的道路,长度为Ti。

    输出格式

    一个整数,表示最长的最短路得长度。

    输入输出样例

    输入 #1

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

    输出 #1

    10

    说明/提示

    SPFA

    【注意注意】

    这是单向路单向路单向路!!!
    重要的事情说三遍!!!
    (题目中没点出这点但是我的全WA经历让我深刻的认识到了这一点)

    【思路】

    去和来这是两个完全相反的东西
    SPFA跑一个方向是很轻松的
    然后另一个方向就很难办了
    该怎么办呢?
    n遍SPFA?
    不太可能这就是一道黄题
    对了!可以反向建图!
    将方向反过来建出来的图就是完全相反的
    某个点到x的距离恰好就是回家的最短距离
    这样和正向建图一结合
    就能求出去和回的最短路径了
    然后比较最大的和
    输出就好了

    【完整代码】

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    using namespace std;
    const int Max = 100005;
    struct node
    {
    	int y;
    	int ne;
    	int z;
    }a1[Max << 1],a2[Max << 1];
    int n,m,x;
    const int M = 1002;
    int head1[M],head2[M];
    int sum = 0;
    void add1(int x,int y,int z)
    {
    	a1[++ sum].y = y;
    	a1[sum].z = z;
    	a1[sum].ne = head1[x];
    	head1[x] = sum;
    }
    void add2(int x,int y,int z)
    {
    	a2[++ sum].y = y;
    	a2[sum].z = z;
    	a2[sum].ne = head2[x];
    	head2[x] = sum;
    }
    
    int d1[M],d2[M];
    bool use[M];
    void SPFA1()
    {
    	memset(use,false,sizeof(use));
    	queue<int>q;
    	for(register int i = 1;i <= n;++ i)
    		d1[i] = 999999;
    	d1[x] = 0;
    	q.push(x);
    	while(!q.empty())
    	{
    		int qwq = q.front();
    		q.pop();use[qwq] = false;
    		for(register int i = head1[qwq];i != 0;i = a1[i].ne)
    		{
    			int awa = a1[i].y;
    			if(d1[awa] > d1[qwq] + a1[i].z)
    			{
    				d1[awa] = d1[qwq] + a1[i].z;
    				if(use[awa] == false)
    				{
    					use[awa] = true;
    					q.push(awa);
    				}
    			}
    		}
    	}
    }
    void SPFA2()
    {
    	memset(use,false,sizeof(use));
    	queue<int>q;
    	for(register int i = 1;i <= n;++ i)
    		d2[i] = 999999;
    	d2[x] = 0;
    	q.push(x);
    	while(!q.empty())
    	{
    		int qwq = q.front();
    		q.pop();use[qwq] = false;
    		for(register int i = head2[qwq];i != 0;i = a2[i].ne)
    		{
    			int awa = a2[i].y;
    			if(d2[awa] > d2[qwq] + a2[i].z)
    			{
    				d2[awa] = d2[qwq] + a2[i].z;
    				if(use[awa] == false)
    				{
    					use[awa] = true;
    					q.push(awa);
    				}
    			}
    		}
    	}
    }
    
    int main()
    {
    	scanf("%d%d%d",&n,&m,&x);
    	int xx,yy,zz;
    	for(register int i = 1;i <= m;++ i)
    	{
    		scanf("%d%d%d",&xx,&yy,&zz);
    		add1(xx,yy,zz);
    		add2(yy,xx,zz);
    	}
    	SPFA1();
    	SPFA2();
    	int MM = 0;
    	for(register int i = 1;i <= n;++ i)
    		MM = max(MM,d1[i] + d2[i]);
    	cout << MM << endl;
    	return 0;
    }
    
  • 相关阅读:
    linux内核(四)内存管理单元MMU
    open函数详解
    linux内核(三)文件系统
    C++中数字与字符串之间的转换 scanf string总结(复习必读)
    hello程序的运行过程-从计算机系统角度
    剑指offer第12题打印从1到n位数以及大整数加法乘法
    2017-10-11第二次万革始面经
    为什么需要半关闭
    Ubuntu指令
    143. Reorder List
  • 原文地址:https://www.cnblogs.com/acioi/p/11692207.html
Copyright © 2011-2022 走看看