这是地址
期末复习了几天没敲代码,就去写个题单找找感觉…
感觉还是有所提升的吧…暴露了好多问题出来
只挑几个题来记录吧
floyd求多源最短路吧,只不过这个题有所改变,需要对floyd有足够的理解才能写,暴力的话肯定要T
因为给出了每个村庄重建的时间,那我们就先初始化所有村庄为-1,即不可运输,然后对于每个给出的时间,我们把新加入的村庄作为松弛点,进行松弛,不能每次都以所有的点进行松弛,不然会超时
还好出题人比较良心,给出的时间以及村庄重建的时间都是非递减的,这样就省去了很多麻烦
#include <bits/stdc++.h>
#define ms(arr, x) memset(arr, x, sizeof(arr))
using namespace std;
typedef long long LL;
const int inf = 0x3f3f3f3f;
int e[205][205], vis[205], Time[205], n, m, now = 0, T = 0;
void floyd(int a, int b) {
for(int k = a; k <= b; ++ k) {
for(int i = 1; i <= n; ++ i) {
//if(!vis[i]) continue;
for(int j = 1; j <= n; ++ j) {
//if(!vis[j]) continue;
e[j][i] = e[i][j] = min(e[i][j], e[i][k] + e[k][j]);
}
}
}
}
void run() {
while(now < n && Time[now + 1] <= T) {vis[++ now] = 1;floyd(now, now);}
}
int main () {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++ i){
scanf("%d",&Time[i]);
vis[i] = 0;
for(int j = 1; j <= n; ++ j) {
e[i][j] = i == j ? 0 : inf;
}
}
Time[n + 1] = inf;
while(m --) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
++ u, ++ v;
e[u][v] = e[v][u] = min(e[u][v], w);
}
int question;
scanf("%d", &question);
while(question --) {
int x, y, t;
scanf("%d %d %d", &x, &y, &t);
++ x, ++ y;
T = t;
run();
if(!vis[x] || !vis[y]) {
puts("-1");
continue;
}
printf("%d\n", e[x][y] == inf ? -1 : e[x][y]);
}
#ifdef _LOCALE_PAUSE_
system("pause");
#endif // PAUSE;
return 0;
}
注意是有向图,并且需要返回到起始点,所以我们需要离线操作,储存下读入的边,然后跑两边dij,一次正向建图,一次反向建图,就可以分别求出,1到其他点和其他点到1的最短路径了(针对于有向图,无向图不需要跑两遍
#include <bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 1e3 + 7;
const int maxm = 1e5 + 7;
int n, m;
struct pqnode {
int u, w;
pqnode(int _u = 0, int _w = 0) : u(_u), w(_w) {}
bool operator < (const pqnode& b) const {
return w > b.w;
}
};
struct Edge {
int v, w;
Edge(int _v = 0, int _w = 0) : v(_v), w(_w) {}
};
vector<Edge> G[maxn];
int dis[maxn], vis[maxn];
void dijstra(int st) {
for(int i = 1; i <= n; ++ i) {
dis[i] = inf;
vis[i] = 0;
}
dis[st] = 0;
priority_queue<pqnode> pq; while(!pq.empty()) {pq.pop();}
pq.push(pqnode(st, 0));
pqnode tmp;
while(!pq.empty()) {
tmp = pq.top();
pq.pop();
int u = tmp.u;
if(vis[u]) {
continue;
}
vis[u] = 1;
int sz = G[u].size();
for(int i = 0; i < sz; ++ i) {
int v = G[u][i].v, w = G[u][i].w;
if(!vis[v] && dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
pq.push(pqnode(v, dis[v]));
}
}
}
}
struct INPUT {
int u, v, w;
}input[maxm];
int main () {
scanf("%d %d", &n, &m);
for(int i = 1; i <= m; ++ i) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
input[i] = (INPUT) {u, v, w};
G[u].push_back(Edge(v, w));
//G[v].push_back(Edge(u, w));
}
dijstra(1);
int res = 0;
for(int i = 1; i <= n; ++ i) {
res += dis[i];
}
//
for(int i = 1; i <= n; ++ i) {
G[i].clear();
}
for(int i = 1; i <= m; ++ i) {
int u = input[i].u, v = input[i].v, w = input[i].w;
G[v].push_back(Edge(u, w));
//G[v].push_back(Edge(u, w));
}
dijstra(1);
for(int i = 1; i <= n; ++ i) {
res += dis[i];
}
printf("%d\n", res);
#ifdef _LOCALE_PAUSE_
system("pause");
#endif // PAUSE
return 0;
}
最短路计数,还是要熟悉下大致咋写才行
因为这题权值都为1,所以也可以用bfs分层,然后记录方案数,我用bfs和dij都交了一发,这里都贴上吧
bfs 初始化起点为0,并用标记数组标记一下
然后放入队列不断扩展,对于队列中每一个进行扩展的元素,如果他相连的点没被标记过,就标记下来,并且使这个点方案数等于目前这个元素的方案数,层数为目前加一,再放入队列
如果被标记过且层数等于当前层数加一,就把这个点的方案数大小增加当前元素的方案数
for(int i = 0; i < sz; ++ i) {
int v = G[u][i];
if(!vis[v]) {
vis[v] = 1;
dep[v] = dep[u] + 1;
que.push(v);
}
if(dep[v] == dep[u] + 1) {
res[v] += res[u];
res[v] %= mod;
}
}
全部代码是
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn = 1e6 + 7;
const LL mod = 1e5 + 3;
vector<int> G[maxn];
int vis[maxn], dep[maxn];
LL res[maxn];
int main () {
int n, m; scanf("%d %d", &n, &m);
memset(res, 0, sizeof(res));
memset(vis, 0, sizeof(vis));
memset(dep, 0, sizeof(dep));
while(m --) {
int u, v;
scanf("%d %d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
res[1] = 1, vis[1] = 1;
queue<int> que;
que.push(1);
while(!que.empty()) {
int u = que.front();
que.pop();
int sz = G[u].size();
for(int i = 0; i < sz; ++ i) {
int v = G[u][i];
if(!vis[v]) {
vis[v] = 1;
dep[v] = dep[u] + 1;
que.push(v);
}
if(dep[v] == dep[u] + 1) {
res[v] += res[u];
res[v] %= mod;
}
}
}
for(int i = 1; i <= n; ++ i) {
printf("%lld\n",res[i]);
}
#ifdef _LOCALE_PAUSE_
system("pause");
#endif // PAUSE
return 0;
}
dij写法就是和原始的写法差不多,区别在于,单独开个res数组代表方案数,清0,起点方案数为1,然后在松弛的时候,如果dis[v]>dis[u]+cost,就更新dis数组,并且把v的方案数改为u的方案数,如果相等,就把u的方案数加在v上面
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL mod = 1e5 + 3;
const int maxn = 1e6 + 7;
const int maxm = 2e6 + 7;
int n, m;
struct pqnode {
int u, w;
pqnode(int _u = 0, int _w = 0) : u(_u), w(_w) {}
bool operator < (const pqnode&b) const {
return w > b.w;
}
};
struct Edge {
int v, w;
Edge(int _v = 0, int _w = 0) : v(_v), w(_w) {}
};
vector<Edge> G[maxn];
priority_queue<pqnode> pq;
bool vis[maxn];
LL res[maxn];
int dis[maxn];
void dijstra(int st) {
for(int i = 1; i <= n; ++ i) {
dis[i] = 0x3f3f3f3f;
vis[i] = false;
res[i] = 0;
}
dis[st] = 0;
res[st] = 1;
pq.push(pqnode(1, 0));
pqnode tmp;
while(!pq.empty()) {
tmp = pq.top();
pq.pop();
int u =tmp.u;
if(vis[u]) {
continue;
}
vis[u] = true;
int sz = G[u].size();
for(int i = 0; i < sz; ++ i) {
int v = G[u][i].v, w = G[u][i].w;
if(!vis[v]) {
if(dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
res[v] = res[u];
pq.push(pqnode(v, dis[v]));
} else if(dis[v] == dis[u] + w) {
res[v] += res[u];
res[v] %= mod;
}
}
}
}
}
int main () {
scanf("%d %d", &n, &m);
while(m --) {
int u , v;
scanf("%d %d", &u, &v);
if(u == v) {
continue;
}
G[u].push_back(Edge(v, 1));
G[v].push_back(Edge(u, 1));
}
dijstra(1);
for(int i = 1; i <= n; ++ i) {
printf("%lld\n",res[i]);
}
#ifdef _LOCALE_PAUSE_
system("pause");
#endif // PAUSE
return 0;
}
二分逼近答案,我们可以二分答案(金钱),然后看这个金钱下能否到达终点,关于金钱,我们只需要在每一次松弛的时候,判断松弛点的城市 金钱是否超过了限制,超过了的话就不能进行松弛并且也不能放进队列,最后判断dis[n]是否小于血量(不能等于,,等于就挂了)
注意需要判断下起点1的金钱是否满足放入队列的条件,,特判一下,或者直接把二分的left设置为1的金钱就可以了
#include <bits/stdc++.h>
typedef long long LL;
using namespace std;
const int maxn = 1e4 + 7;
const int maxm = 5e4 + 7;
struct qnode{
int u;
LL w;
qnode(int _u = 0, LL _w = 0) : u(_u) , w(_w) {}
};
struct EDGE{
int v;
LL w;
EDGE(int _v = 0, LL _w = 0) : v(_v), w(_w) {}
};
vector<EDGE> G[maxn];
bool vis[maxn];
LL dis[maxn];
LL fi[maxn];
int n, m, b;
bool spfa(LL val, int st) {
for(int i = 1; i <= n; ++ i) {
dis[i] = 1e14 + 7;
vis[i] = false;
}
dis[st] = 0;
queue<qnode> que;
que.push(qnode(st, 0));
qnode tmp;
while(!que.empty()) {
tmp = que.front();
que.pop();
int u = tmp.u;
vis[u] = false;
int sz = G[u].size();
for(int i = 0; i < sz; ++ i) {
int v = G[u][i].v;
LL w = G[u][i].w;
if(fi[v] > val) {
continue;
}
if(dis[v] > dis[u] + w) {
dis[v] = dis[u] + w;
if(!vis[v]) {
vis[v] = true;
que.push(qnode(v, dis[v]));
}
}
}
}
return dis[n] < b;
}
int main () {
scanf("%d %d %d", &n, &m, &b);
LL R = 0;
for(int i = 1; i <= n; ++ i) {
scanf("%lld", &fi[i]);
R = max(R, fi[i]);
}
LL L = fi[1];
while(m --) {
int u, v;
LL w;
scanf("%d %d %lld", &u, &v, &w);
G[u].push_back(EDGE(v, w));
G[v].push_back(EDGE(u, w));
}
LL res = -1;
while(L <= R) {
int mid = L + (R - L) / 2;
if(spfa(mid, 1)) {
res = mid;
R = mid - 1;
} else {
L = mid + 1;
}
}
if(res == -1) {
puts("AFK");
} else {
printf("%lld\n", res);
}
#ifdef _LOCALE_PAUSE_
system("pause");
system("pause");
#endif // PAUSE;
return 0;
}