#include<iostream>#include<cstdio>#include<cstring>usingnamespace std;intread(void){int x =0, c =getchar();while(!isdigit(c)) c =getchar();while(isdigit(c)) x = x *10+ c -'0', c =getchar();return x;}int n, m;int d[205][205];int t[205];intmain(void){
n =read(), m =read();memset(d,0x3f,sizeof(d));for(int i =0; i < n;++i){
t[i]=read();
d[i][i]=0;}while(m--){int x =read(), y =read(), v =read();
d[x][y]= v;
d[y][x]= v;}int q =read(), k =0;while(q--){int x =read(), y =read(), T =read();for(; t[k]<= T && k < n;++k)// 核心for(int i =0; i < n;++i)for(int j =0; j < n;++j)
d[i][j]=min(d[i][j], d[i][k]+ d[k][j]);if(t[x]> T || t[y]> T || d[x][y]==0x3f3f3f3f)puts("-1");// 可能这个村庄依旧处于报废elseprintf("%d\n", d[x][y]);}return0;}
#include<iostream>#include<cstdio>#include<string>#include<cstring>#include<vector>usingnamespace std;int n, m, kase;
vector <string> names;bool f[30][30], vis[30];char a[100], b[100];intID(const string &s){for(int i =0; i < names.size();++i)if(names[i]== s)return i;
names.push_back(s);return names.size()-1;}voiddfs(int u){
vis[u]=true;for(int v =0; v < n;++v)if(!vis[v]&& f[u][v]&& f[v][u]){
cout <<", "<< names[v];dfs(v);}}intmain(void){while(scanf("%d%d",&n,&m)==2&& n){
names.clear();memset(f,0,sizeof(f));for(int i =0; i < n;++i) f[i][i]=1;while(m--){scanf("%s%s", a, b);
f[ID(a)][ID(b)]=1;}for(int k =0; k < n;++k)for(int i =0; i < n;++i)for(int j =0; j < n;++j)
f[i][j]|= f[i][k]& f[k][j];if(kase)putchar('\n');printf("Calling circles for data set %d:\n",++kase);memset(vis,0,sizeof(vis));for(int i =0; i < n;++i)if(!vis[i]){
cout << names[i];dfs(i);putchar('\n');}}return0;}
#include<iostream>#include<cstdio>#include<cstring>usingnamespace std;intread(void){int x =0, c =getchar_unlocked();while(!isdigit(c)) c =getchar_unlocked();while(isdigit(c)) x = x *10+ c -'0', c =getchar_unlocked();return x;}int n, m, w;int f[505][505];intmain(void){int T =read();while(T--){memset(f,0x3f,sizeof(f));
n =read(), m =read(), w =read();while(m--){int x =read(), y =read(), v =read();
f[x][y]=min(f[x][y], v);
f[y][x]=min(f[y][x], v);}while(w--){int x =read(), y =read();
f[x][y]=min(f[x][y],-read());}for(int k =1; k <= n;++k)for(int i =1; i <= n;++i)for(int j =1; j <= n;++j)
f[i][j]=min(f[i][j], f[i][k]+ f[k][j]);bool flag =true;for(int i =1; i <= n;++i)if(f[i][i]<0){puts("YES");
flag =false;break;}if(flag)puts("NO");}return0;}
#include<bits/stdc++.h>usingnamespace std;inlineintread(void){int x =0, c =getchar(), f =1;while(!isdigit(c)){if(c =='-') f =-1; c =getchar();}while(isdigit(c)) x =(x<<3)+(x<<1)+(c^48), c =getchar();return x * f;}structedge{int from, to, dist;edge(int from =0,int to =0,int dist =0):from(from),to(to),dist(dist){}};int n, m;int d[10005], inq[10005];
vector <edge> G[10005];int cnt[100005];inlinevoidaddedge(int u,int v,int d){
G[u].push_back(edge(u, v, d));}boolSPFA(){memset(d,0x3f,sizeof(d));memset(cnt,0,sizeof(cnt));memset(inq,0,sizeof(inq));
d[1]=0;
inq[1]=true;
queue <int> q;
q.push(1);while(!q.empty()){int u = q.front(); q.pop(); inq[u]=false;for(int i =0; i < G[u].size();++i){
edge &e = G[u][i];if(d[e.to]> d[u]+ e.dist){
d[e.to]= d[u]+ e.dist;
cnt[e.to]= cnt[u]+1;if(cnt[e.to]> n)returntrue;if(!inq[e.to]){
inq[e.to]=1;
q.push(e.to);}}}}returnfalse;}intmain(void){int T =read();while(T--){
n =read(), m =read();for(int i =1; i <= n;++i)
G[i].clear();while(m--){int u =read(), v =read(), w =read();addedge(u, v, w);if(w >=0)addedge(v, u, w);}puts(SPFA()?"YES":"NO");}return0;}
要注意的是,如果图中有负环但是起点 s 走不到这个负环,那么无法找到。解决方法是外挂一个节点,跟每一个点都连一条边,然后对这个点跑 SPFA。
int v[5005], d[5050];memset(d,0x3f,sizeof(d));memset(a,0x3f,sizeof(a));read_graph();memset(v,0,sizeof(v));
d[1]=0;for(int op =1; op < n;++op)// 迭代 n-1 次{int x =0;// 找 xfor(int i =1; i <= n;++i)if(v[i]==0&&(x ==0|| d[i]< d[x])) x = i;
v[x]=1;// 松弛for(int i =1; i <= n;++i)
d[i]=min(d[i], d[x]+ a[x][i]);}
将原图复制 k 次,原来编号为 i 的节点复制为编号 i+jn 的节点。然后第 j 层和第 j+1 层的对应节点也要连上边,边权值为 0,而且是单向边(最多免费乘坐 k 次)。
查看代码
#include<iostream>#include<cstdio>#include<vector>#include<queue>#include<cstring>usingnamespace std;structedge{int to, dist;edge(int to =0,int dist =0):to(to),dist(dist){}};int n, m, k, s, t;int d[110005];bool v[110005];
vector <edge> G[110005];inlinevoidaddedge(int u,int v,int d){
G[u].push_back(edge(v, d));}voidDijkstra(void){#definepiipair<int,int>
priority_queue <pii, vector<pii>, greater<pii>> q;memset(d,0x3f,sizeof(d));
d[s]=0;
q.push(make_pair(0, s));while(!q.empty()){int u = q.top().second; q.pop();if(!v[u]){
v[u]=true;for(int i =0; i < G[u].size();++i){
edge &e = G[u][i];if(d[e.to]> d[u]+ e.dist){
d[e.to]= d[u]+ e.dist;
q.push(make_pair(d[e.to], e.to));}}}}}intmain(void){scanf("%d%d%d%d%d",&n,&m,&k,&s,&t);for(int i =0, u, v, d; i < m;++i){scanf("%d%d%d",&u,&v,&d);addedge(u, v, d);addedge(v, u, d);for(int j =1; j <= k;++j){addedge(u + j * n, v + j * n, d);addedge(v + j * n, u + j * n, d);addedge(u +(j -1)* n, v + j * n,0);addedge(v +(j -1)* n, u + j * n,0);}}Dijkstra();int ans =0x7fffffff;for(int i =0; i <= k;++i)
ans =min(ans, d[t + i * n]);printf("%d\n", ans);return0;}
#include<bits/stdc++.h>usingnamespace std;constdouble eps =1e-6;constdouble INF =1e9;int n, m, t;bool inq[1005];structedge{int v, type;double w;edge(int v =0,double w =0,int type =0):v(v),w(w),type(type){}};
vector<edge> G[1005];double d[1005];int cnt[1005];boolSPFA(double T){for(int i =0; i <= n;++i) cnt[i]=0, d[i]=-INF; d[n +1]=0;
queue<int> q; q.push(n +1); inq[n +1]=true;while(!q.empty()){int u = q.front(); q.pop(); inq[u]=false;for(int i =0; i < G[u].size();++i){int v = G[u][i].v, type = G[u][i].type;double w = G[u][i].w;if(type ==1) w =log2(w - T);elseif(type ==2) w =-log2(w + T);if(d[v]< d[u]+ w){
d[v]= d[u]+ w, inq[v]=true, q.push(v);if((cnt[v]= cnt[u]+1)> n +1)return1;// 肯定有人女装 }}}return0;}intmain(void){scanf("%d%d%d",&n,&m,&t);for(int i =0; i <= n;++i) G[n +1].emplace_back(i,0);while(m--){int o, a, b, k;scanf("%d%d%d%d",&o,&a,&b,&k);
G[b].emplace_back(a, k, o);}while(t--){int c;double x;scanf("%d%lf",&c,&x);
G[0].emplace_back(c,log2(x)); G[c].emplace_back(0,-log2(x));}double L =0, R =10, mid;if(!SPFA(0))returnputs("-1"),0;while(L + eps < R){if(SPFA(mid =(L + R)/2)) L = mid;else R = mid;}printf("%.6lf\n", L);return0;}
秋名山上有 n 个点和 m 条边,james1 和 Mr. V 要从点 1 出发开往点 n,每条边都有一个初始的方向。Solaris 拿到了秋名山的地图但却不知道每条路有多长。显然,为了赛车游戏的公平,每条 1 到 n 的路径应当是等长的。Solaris 想,我就随便给边表上一个 1…9 的长度,反正傻傻的 james1 也看不出来。
给定一张 n(1≤n≤105) 点 m(1≤m≤105) 边的有向带权图,给定其中 k(2≤k≤n) 个点,问这 k 个点两两之间的最短路的最小一个的长度。
如果我们把特殊点分成 A,B 两个集合,新建起点 s 连接到 A 上的所有点,B 中所有点连到 t,那么 s,t 的最短路就是 A,B 之间点对的最小最短路。
我们枚举二进制位,将第 i 位为 1 的放在 A,其余放在 0,这样就能保证总有一种情况两个点不在一个集合里,可以覆盖所有的情况。
然而这样很慢,我们换一种思路。我们求出点 i 到某个关键点的最短距离 ti 和到的关键点 toi,以及到点 i 最近的关键点 fri 和距离 fi。我们只需要用一条边把两个最短拼接在一起即可。显然不存在一条比这更短的路径,否则我们一定可以将原来最短路中的一条边替换,变成更短的路。而且也肯定不会漏解,因为最优解一定是“从一个关键点出发,经过一条边,再到另一个关键点”。
查看代码
#include<bits/stdc++.h>usingnamespace std;using i64 =longlong;using pii = pair<int,int>;using pli = pair<i64,int>;int n, m, k;int u[500005], v[500005], d[500005];int a[100005];structDijkstra{
i64 d[100005];int f[100005];bool vis[100005];
vector<pii> G[100005];voidinit(void){for(int i =1; i <= n;++i)
G[i].clear();}voiddijkstra(void){memset(d,0x1f,sizeof(d));memset(vis,0,sizeof(vis));
priority_queue<pli, vector<pli>, greater<pli>> q;for(int i =1; i <= k;++i){
d[a[i]]=0; f[a[i]]= a[i];
q.push(make_pair(0, a[i]));}while(!q.empty()){int u = q.top().second; q.pop();if(!vis[u]){
vis[u]=true;for(int i =0; i < G[u].size();++i){int v = G[u][i].first, w = G[u][i].second;if(d[v]> d[u]+ w){
d[v]= d[u]+ w;
q.push(make_pair(d[v], v));
f[v]= f[u];}}}}}} S1, S2;voidsolve(void){scanf("%d%d%d",&n,&m,&k);
S1.init(), S2.init();for(int i =1; i <= m;++i){scanf("%d%d%d", u + i, v + i, d + i);
S1.G[u[i]].push_back({v[i], d[i]});
S2.G[v[i]].push_back({u[i], d[i]});}for(int i =1; i <= k;++i)scanf("%d", a + i);
S1.dijkstra(); S2.dijkstra();// S1 为关键点到点 i,S2 为从点 i 到关键点
i64 ans =4e18;for(int i =1; i <= m;++i)if(S1.f[u[i]]!= S2.f[v[i]])
ans =min(ans, S1.d[u[i]]+ S2.d[v[i]]+ d[i]);printf("%lld\n", ans);}intmain(void){int T;scanf("%d",&T);while(T--)solve();return0;}
#include<bits/stdc++.h>usingnamespace std;constint INF =1e7;constint DX[]={0,0,1,-1}, DY[]={1,-1,0,0};int n, m, t;int sx, sy, px[15], py[15], v[15];char a[25][25];int f[25][25][1024], sum[1024];inlineboolcheck(int x,int y,int xx,int yy,int i){if(xx == px[i]&& yy < py[i]&& x < xx)return1;if(x == px[i]&& y < py[i]&& x > xx)return1;return0;}intbfs(void){int ans =-INF;structstate{int x, y, s;state(int x =0,int y =0,int s =0):x(x),y(y),s(s){}};memset(f,0xff,sizeof f); f[sx][sy][0]=0;
queue<state> q; q.emplace(sx, sy,0);while(!q.empty()){
state u = q.front(); q.pop();int x = u.x, y = u.y, s = u.s;if(x == sx && y == sy) ans =max(ans, sum[s]- f[x][y][s]);for(int i =0; i <4;++i){int xx = x + DX[i], yy = y + DY[i], ss = s;if(xx <1|| xx > n || yy <1|| yy > m)continue;if(a[xx][yy]!='.'&& a[xx][yy]!='S')continue;for(int j =0; j < t;++j)if(check(x, y, xx, yy, j)) ss ^=1<< j;if(f[xx][yy][ss]==-1) f[xx][yy][ss]= f[x][y][s]+1, q.emplace(xx, yy, ss);}}return ans;}intmain(void){scanf("%d%d",&n,&m);for(int i =1; i <= n;++i)scanf("%s", a[i]+1);for(int i =1; i <= n;++i)for(int j =1; j <= m;++j){char&c = a[i][j];if(c =='S') sx = i, sy = j;elseif(isdigit(c)) px[c -'0'-1]= i, py[c -'0'-1]= j,++t;}for(int i =0; i < t;++i)scanf("%d", v + i);for(int i =1; i <= n;++i)for(int j =1; j <= m;++j)if(a[i][j]=='B') px[t]= i, py[t]= j, v[t]=-INF,++t;for(int i =0; i <1<< t;++i)for(int j =0; j < t;++j)if(i >> j &1) sum[i]+= v[j];return!printf("%d\n",bfs());}