****首先,感谢pxgg一直以来的支持和帮助*****
题目链接
*题目大意,N头奶牛,从各自地点(就是他们的编号1,2,--N),沿着一条单向路,前去X(1<=X<=N)地,
*参加party,party后,N头奶牛,沿着一条单向路回到原地。问来回需要最小的时间。
数据范围:1 ≤ N ≤ 1000,1 ≤ M ≤ 100,000,Ti,1 ≤ Ti ≤ 100;依次为点的数目,边的数目,一条路所需时间。
时间要求:2000ms;
所用算法:Floyd,O(N^3)超时;bellman,O(N*M),超时;**dijkstra**,优化前,O(N^2),可跑,**优化**后,O((N+M)log2(N)),强。
题目要求:(1) 求出n头奶牛到一个地点的距离sum1,
(2) 求出n头奶牛从一个地点到n个地点的距离sum2。
(3) 输出sum1+sum2;
第(2)个问题容易解决,就是跑一边dijkstra,算出X点到n个点的最小距离的和。
第(1)个问题求的是n个点到1个点X的距离,我们这样想:
有4的点,1,2,3,4,要去2号点,已知最短路线如下:
这些路径是单向的,如果我们求每个点到2的最短距离,最多跑n次,dijkstra复杂度也不行,肯定会超。
路径的长度是一定的,那么我们这样想,现在让牛走到2号点的时候沿着原路返回。走的这些距离就是sum1;
1-->3-->2;
2;
3-->4-->2;
4-->1-->2;
这些路径就成了:
2-->3-->1;
2;
2-->4-->3;
2-->1-->4;
我们的问题又变成了求2号点到各个顶点的距离。
***但是要把所有的边都逆向处理,因为如果不处理的话,怎么求啊,哈哈哈哈哈哈哈哈哈。***
//做题的时候用vector存的图,写博客时想着用邻接表写一下,结果改了半个多小时,我太菜了。
//手写邻接表,和vector实现邻接表不太一样,使用vector,会额外增加一些时间,
//用vector的版本,跑了32ms;手写邻接表,跑了16ms;
#include
#include
#include
#include
using namespace std;
const int num_e=100000+10;
const int num_p=1010;
const int inf=0x3f3f3f3f;
struct node
{
int v,w,next;
node(){};
node(int a,int b)
{
v=a;w=b;
}
bool operator < (const node & s) const
{
return w > s.w;
}
}edge[num_e];
int head[num_p];
int from[num_e],to[num_e],worth[num_e];
int date[2][num_e];
int n,m,x,cnt;
void int_i(void)
{
cnt=0;
for(int j=1;j<=n;j++)
head[j]=0;
return ;
}
void addedge(int a,int b,int c)
{
edge[++cnt].v=b;
edge[cnt].w=c;
edge[cnt].next=head[a];
head[a]=cnt;
return ;
}
void dijkstra(int g)
{
int dis[n+1];
int book[n+1];
for(int i=1;i<=n;i++)
{
dis[i]=inf;
book[i]=0;
}
dis[x]=0;
priority_queue<node>q;//一定要用优先队列啊,就是因为这里调了半个小时,感谢pxgg。
q.push(node(x,0));
while(!q.empty())
{
node x=q.top();q.pop();
if(book[x.v])
continue;
book[x.v]=1;
for(int i=head[x.v];i;i=edge[i].next)
{
int y=edge[i].v;
if(book[y]) continue;
if(dis[y] > x.w + edge[i].w)
{
dis[y]=x.w + edge[i].w;
q.push(node(y,dis[y]));
}
}
}
for(int i=1;i<=n;i++)
{
date[g][i]=dis[i];
}
return ;
}
int main()
{
scanf("%d%d%d",&n,&m,&x);
int_i();
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&from[i],&to[i],&worth[i]);
addedge(from[i],to[i],worth[i]);
}
dijkstra(0);
int_i();
//将边倒着存储,再跑一次
for(int i=1;i<=m;i++)
{
addedge(to[i],from[i],worth[i]);
}
dijkstra(1);
int maxm=0;
for(int i=1;i<=n;i++)
maxm=max(maxm,date[0][i]+date[1][i]);
printf("%d\n",maxm);
return 0;
}
//vector版本,跑了32ms
#include
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int inf=0x3f3f3f3f;
const int num=1010;
struct edge
{
int u,v,w;
edge(int a,int b,int c)
{
u=a;v=b;w=c;
}
};
vector<edge>e[num];
int from[num],to[num],time[num];//´æ´¢Êý¾Ý
int date[2][num];
struct point
{
int id,n_dis;
point(int a,int b)
{
id=a;n_dis=b;
}
bool operator < (const point &a) const
{
return n_dis > a.n_dis;
}
};
void dijkstra(int g,int x,int n)
{
int dis[num];
bool book[num];
for(int i=1;i<=n;i++)
{
dis[i]=inf;
book[i]=false;
}
dis[x]=0;
priority_queue<point>q;
q.push(point(x,0));
while(!q.empty())
{
point x=q.top();
q.pop();
if(book[x.id])
continue;
book[x.id]=true;
for(int i=0;i<e[x.id].size();i++)
{
edge y=e[x.id][i];
if(book[y.v])
continue;
if(dis[y.v] > x.n_dis + y.w)
{
dis[y.v] = x.n_dis + y.w;
q.push(point(y.v,dis[y.v]));
}
}
}
for(int i=1;i<=n;i++)
date[g][i]=dis[i];
return ;
}
int main()
{
int x,n,m;
int u,v,w;
int sum=0;
scanf("%d%d%d",&n,&m,&x);
for(int i=1;i<=n;i++)
{
e[i].clear();
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&from[i],&to[i],&time[i]);
e[to[i]].push_back(edge(to[i],from[i],time[i]));
}
dijkstra(0,x,n);
for(int i=1;i<=n;i++)
{
e[i].clear();
}
for(int i=1;i<=m;i++)
{
e[from[i]].push_back(edge(from[i],to[i],time[i]));
}
dijkstra(1,x,n);
sum=0;
for(int i=1;i<=n;i++)
sum=max(date[0][i]+date[1][i],sum);
printf("%d\n",sum);
return 0;
}