题目链接
题意
给你
n
n
n 个点
0
0
0 到
n
−
1
n-1
n−1 ,
m
m
m 个行政人员
0
0
0 到
m
−
1
m-1
m−1,
q
q
q 条边。
接下来一行
m
m
m 个整数,代表
e
i
e_i
ei
接下来一行
m
m
m 个整数,代表
f
i
f_i
fi
接下来
q
q
q 行,每行
4
4
4 个整数,
u
u
u,
v
v
v,
z
z
z,
d
d
d,表示
u
u
u 到
v
v
v 有条单向边,归第
z
z
z 个行政人员管,边权为
d
d
d
求
0
0
0 号点到
n
−
1
n-1
n−1 号点建立联系的最小花费,即最短路。
两点间最短路除了花费
d
d
d 以外,还需要加上
e
e
e
f
f
f
第
m
i
m_i
mi 个行政人员第二次工作需要花费
d
+
e
i
d+e_i
d+ei,超过三次工作需要花费
d
+
f
i
d+f_i
d+fi
思路
先三进制状态压缩,工作0次,1次,>1次。
求最短路时,多考虑一个所有行政人员工作状态(次数)
求
d
i
s
[
行
政
人
员
状
态
]
[
当
前
点
]
dis[行政人员状态][当前点]
dis[行政人员状态][当前点],跑个dijkstra即可。
后台数据好像略水,应该没有超过 n > 10 n>10 n>10 的?,数组开小了竟然A了。
#include <stdio.h>
#include <vector>
#include <queue>
#include <string.h>
using namespace std;
int read(int &_a){return scanf("%d",&_a);}
int rd(){int _tmp; scanf("%d",&_tmp); return _tmp;}
struct Node
{
int v, id, d;
}node;
vector<Node> e[105]; // 存图
int w[10], f[10]; // 存权值
// vis[行政人员状态][当前点] 表示来过没,感觉瞎搞下可以用dis代替
// dis[行政人员状态][当前点] 表示最短路
int three[15], dig[60000][15], vis[60000][105], dis[60000][105];
struct Point
{
int u, dis, wtf;
Point(){}
Point(int _a, int _b, int _c):u(_a),dis(_b),wtf(_c){}
bool operator <(const Point &a) const
{
return dis > a.dis;
}
}st, ne;
int get(int wtf, int id)
{
if(dig[wtf][id] == 0) return 0;
if(dig[wtf][id] == 1) return w[id];
return f[id];
}
int main()
{
/*三进制压缩预处理*/
three[0] = 1;
for(int i = 1; i <= 10; ++i) three[i] = 3*three[i-1];
for(int i = 0; i < three[10]; ++i)
{
int tmp = i;
for(int j = 0; j < 10; ++j)
{
dig[i][j] = tmp%3;
tmp /= 3;
}
}
int n, m, q;
while(~scanf("%d%d%d",&n,&m,&q))
{
/*输入*/
for(int i = 0; i < n; ++i) e[i].clear();
for(int i = 0; i < m; ++i) read(w[i]);
for(int i = 0; i < m; ++i) read(f[i]);
for(int i = 0; i < q; ++i)
{
int u = rd();
node.v = rd(), node.id = rd(), node.d = rd();
e[u].push_back(node);
}
/*求最短路*/
priority_queue<Point> q;
q.push(Point(0,0,0));
int flag = 1;
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[0][0] = 0;
while(!q.empty())
{
st = q.top();
q.pop();
if(st.u == n-1)
{
flag = 0;
printf("%d\n",st.dis);
break;
}
if(vis[st.wtf][st.u]) continue;
vis[st.wtf][st.u] = 1;
for(int i = e[st.u].size()-1; ~i; --i) // 多考虑了一个状态,但是和普通最短路算法没啥区别
{
Node v = e[st.u][i];
ne.dis = st.dis+v.d+get(st.wtf,v.id);
ne.wtf = st.wtf;
if(dig[st.wtf][v.id] < 2) ne.wtf = st.wtf+three[v.id];
ne.u = v.v;
if(dis[ne.wtf][ne.u] <= ne.dis) continue;
dis[ne.wtf][ne.u] = ne.dis;
q.push(ne);
}
}
if(flag) printf("-1\n");
}
return 0;
}