瞎搞

2 最短路
short.in/.out/.cpp
2.1 问题描述
给一张n 个点,m 条边的有向图。
每个点有点权vi, 每条边有边权wi。
询问q 次, 每次询问两个点从u 到v 的最短路。
最短路的定义是所有从u 到v 路径的权值的最小值。
一条从u 到v 路径的权值为路径上的边权和+ 路径经过点的最大点权
值(包括u,v)。
若没有从u 到v 的路径, 输出-1。
2.2 输入格式
第一行包含三个整数n,m,q。
接下来n 个正整数表示vi。
接下来m 行, 每行三个正整数a,b,w, 表示有一条从a 到b 权值为w 的
单向边。
接下来q 行, 每行两个数u,v, 表示询问从u 到v 的最短路。
2.3 输出格式
共q 行, 每行一个整数, 表示询问的答案。
2.4 样例输入
4 4 2
1 2 5 8
1 2 2
2 3 3
1 4 1
4 3 1
1 3
2 4
4
2.5 样例输出
10
-1
2.6 数据规模及约定
对于10% 的数据, 满足n5;
对于30% 的数据, 满足n10;
对于另外20% 的数据, 满足若存在(u,v) 则存在(v,
#include <cstdio>  
#include <cmath>  
#include <ctime>  
#include <string>  
#include <cstring>  
#include <cstdlib>  
#include <iostream>  
#include <algorithm>  
  
#include <set> 
#include <stack>  
#include <queue>  
#include <vector>  
#include<map>
#include<list>
 
#define pb push_back 
#define lb lower_bound 
#define sqr(x) (x)*(x) 
#define lowbit(x) (x)&(-x)  
#define Abs(x) ((x) > 0 ? (x) : (-(x)))  
#define forup(i,a,b) for(int i=(a);i<=(b);i++)  
#define fordown(i,a,b) for(int i=(a);i>=(b);i--)  
#define ls(a,b) (((a)+(b)) << 1)  
#define rs(a,b) (((a)+(b)) >> 1)  
#define getlc(a) ch[(a)][0]  
#define getrc(a) ch[(a)][1]  
  
#define maxn 405
#define maxm 100005 
#define INF 1070000000  
using namespace std;  
typedef long long ll;  
typedef unsigned long long ull;  
  
template<class T> inline  
void read(T& num){  
    num = 0; bool f = true;char ch = getchar();  
    while(ch < '0' || ch > '9') { if(ch == '-') f = false;ch = getchar();}  
    while(ch >= '0' && ch <= '9') {num = num * 10 + ch - '0';ch = getchar();}  
    num = f ? num: -num;  
} 
int out[100]; 
template<class T> inline 
void write(T x,char ch){ 
 if (x==0) {putchar('0'); putchar(ch); return;} 
 if (x<0) {putchar('-'); x=-x;} 
 int num=0; 
 while (x){ out[num++]=(x%10); x=x/10;} 
 fordown(i,num-1,0) putchar(out[i]+'0'); putchar(ch); 
} 
/*========================================================*/
struct Node
{int v,id;};Node node[maxn];

int n,m,q;
int v[maxn],dis[maxn][maxn],g[maxn][maxn];
int maxnode[maxn][maxn];
int num[maxn];
bool cmp(Node x,Node y)
{ return x.v<y.v;}

void init()
{read(n); read(m);read(q);
   forup(i,1,n)
    {  read(node[i].v);node[i].id=i;}
    forup(i,1,m)
     {int x,y,z; read(x);read(y);read(z);
       dis[x][y]=min(dis[x][y],z);
	 }
	
}
void solve()
{ 
    sort(node+1,node+n+1,cmp);
    forup(i,1,n)
     forup(j,1,n)
     { int x=node[i].id; int y=node[j].id;
       maxnode[x][y]=max(node[i].v,node[j].v);
       dis[x][y]=dis[x][y]+maxnode[x][y];
	 }
	  forup(k,1,n)
	  forup(i,1,n)
	   forup(j,1,n)
	   { int x=node[k].id,y=node[i].id,z=node[j].id; 
	   if(dis[y][z]>dis[y][x]-maxnode[y][x]+dis[x][z]-maxnode[x][z]+max(maxnode[y][x],maxnode[x][z]))
	     { dis[y][z]=dis[y][x]-maxnode[y][x]+dis[x][z]-maxnode[x][z]+max(maxnode[y][x],maxnode[x][z]);
	        maxnode[y][z]=max(maxnode[y][x],maxnode[x][z]);
		 }
		} 
}

int main()
{
freopen("short.in","r",stdin);
freopen("short.out","w",stdout);

forup(i,1,400)
forup(j,1,400)
{  dis[i][j]=INF;}
 init();
 solve();
    forup(i,1,n)   num[node[i].id]=node[i].v;
    
	forup(i,1,q)
	{int x,y; read(x);read(y);
	  if(x==y)
	   {write(num[x],'\n');continue;} 
	   if(dis[x][y]>=INF/3)
	     { write(-1,'\n');
		 }
		else
		 { write(dis[x][y],'\n');
		  } 
	}
	
	return 0;
 } 


u) 并且wi 相等;
对于60% 的数据, 满足n100;

对于100% 的数据, 满足n400, m n2,



n 400,多源最短路。那么弗洛伊德无疑,但是裸的弗洛伊德肯定是不对的,举个比较。草率地例子,两两合并的时候,其中一边的maxnode非常大,这时可以不用去管另一边的maxnode,那么结果显然就会有和原来暴力佛洛依德偏差,那么怎么办呢。我们已经注意到似乎和最大点有关系了。那么就设法给循环顺序排个序,点权大的排前面(事后发现其实只要外层的k)排序就好了。自己造了几个特殊样例发现能过,然后考试的时候就这么水掉了。。。

事后开始想证明,大约要从弗洛伊德的思想开始,大家都知道佛洛依德是个类似于dp的东西,最外层的k是阶段,可以形象的理解为中间点。那么k递增有什么好处呢。那么显然前面的中间点对后面的就没有影响了。那么貌似就可以直接做了(话说这么胡扯真的算证明吗。。。)


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值