https://hihocoder.com/contest/offers78/problem/4
POINT:
从起点到某个点肯定有多条路,这些路可以抽象为(a,b),a代表经过的路径条数,b代表经过的路径总长度。
那么答案就= a*天数+b。
那么我们就要找到每个点的多对(a,b),当天数较多时,明显a小的有优势,而当天数较少时,可能a大的有优势。
当然这些比较都是在a确定的情况下,b最小。这个可以用最短路处理出来。
然后每询问一个点,我们去遍历这个点的(a,b)对数,取最小的答案。
开dis[x][y],代表走了y条边到x这点的最短距离。
思路就是对于每一个y(每一个a),搜出最小的dis[x][y](最小的b)。
注意到y>=n的时候,就不要搜了,肯定再走重复的路了。
然后我们搜到了所有的dis[x][y],我们对于每一个x,不可能让y=1到y=n,全部都跑一遍。这样肯定是tle的。
维护一个前缀最小值,如果当前的dis[x][y]比这个最小值大,那么这个对就没有价值了。因为之前那个最小值应对的a肯定比这个A小。而b也比这个B=dis[x][y]小。而Ax+B>ax+b一定成立,所以没有价值。(这个对应main函数里的Q次询问之前的预处理操作,主要在qq这个vector里体现)
堆优化重载运算符<是反着的!!,总是忘记,大家当作没看到。
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
const int N = 1111+55;
const int inf = 0x3f3f3f3f;
vectorG[N];
vectorW[N];
struct node
{
int a,b,c;
node(int aa,int bb,int cc)
{
a=aa;b=bb;c=cc;
}
bool friend operator < (node a,node b)
{
return a.a>b.a;
}
};
int n,m,Q;
int dis[N][N],vis[N][N];
void dij()
{
memset(dis,inf,sizeof dis);memset(vis,0,sizeof vis);
dis[1][0]=0;
priority_queueq;
q.push(node(0,1,0));
while(!q.empty()){
node x = q.top();
q.pop();
int u=x.b,p=x.c;
if(vis[u][p]||p>n) continue;
vis[u][p]=1;
for(int i=0;i=dis[u][p]+w){
dis[v][p+1]=dis[u][p]+w;
q.push(node(dis[v][p+1],v,p+1));
}
}
}
}
vector qq[N];
int main()
{
scanf("%d%d%d",&n,&m,&Q);
for(int i=1;i<=m;i++){
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
G[x].push_back(y);G[y].push_back(x);
W[x].push_back(w);W[y].push_back(w);
}
dij();
for(int i=2;i<=n;i++){
int Min=inf;
for(int j=1;j<=n;j++){
if(dis[i][j]>=Min) ;
else{
Min=dis[i][j];
qq[i].push_back(node(j,dis[i][j],0));
}
}
}
while(Q--){
int i,j;scanf("%d%d",&j,&i);
if(j==1) printf("0\n");
else{
LL ans=0x3f3f3f3f3f3f3f3f;
for(int k=0;k