DIJ(拆点) - 行车路线 - 第十二次CCF计算机软件能力认证
题解待补
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
const int N = 510, M = 200010, inf = 1e6;
int n, m;
int e[M], ne[M], type[M], w[M], h[N], idx;
int dis[N][1010]; //dis[i][j]: 从1到i,结尾经过长度为j的小路的代价
//t=0大道:dis[j][0] = dis[i][j] + w
//t=1小道:dis[j][j+w] = dis[i][j] - j^2 + (j+w)^2
bool st[N][1010];
struct edge
{
int id, s_w, d;
bool operator < (const edge & edg) const
{
return d > edg.d;
}
};
void add(int a, int b, int c, int t)
{
e[idx] = b, ne[idx] = h[a], w[idx] = c, type[idx] = t, h[a] = idx ++;
}
void dijkstra()
{
priority_queue<edge> heap;
memset(dis, 0x3f, sizeof dis);
dis[1][0] = 0;
heap.push({1, 0, 1});
while(heap.size())
{
edge edg = heap.top();
heap.pop();
int u = edg.id, s_w = edg.s_w, d = edg.d;
if(st[u][s_w]) continue;
st[u][s_w] = true;
for(int i = h[u]; ~i; i = ne[i])
{
int v = e[i], t = type[i];
if(!t)
{
if(dis[v][0] > dis[u][s_w] + w[i])
{
dis[v][0] = dis[u][s_w] + w[i];
if(dis[v][0] <= inf) heap.push({v, 0, dis[v][0]});
}
}
else
{
if(s_w + w[i] <= 1000)
{
if(dis[v][s_w+w[i]] > dis[u][s_w] - s_w*s_w + (s_w+w[i])*(s_w+w[i]))
{
dis[v][s_w+w[i]] = dis[u][s_w] - s_w*s_w + (s_w+w[i])*(s_w+w[i]);
if(dis[v][s_w+w[i]] <= inf) heap.push({v, s_w+w[i], dis[v][s_w+w[i]]});
}
}
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
memset(h, -1, sizeof h);
int t, a, b, c;
for(int i=0;i<m;i++)
{
scanf("%d%d%d%d", &t, &a, &b, &c);
add(a, b, c, t), add(b, a, c, t);
}
dijkstra();
int res = inf;
for(int i=0;i<=1000;i++) res = min(res, dis[n][i]);
printf("%d\n",res);
return 0;
}