#写在前面
涉及最短路+DFS\二分\DP\拓扑排序
##新年好
https://www.acwing.com/problem/content/1137/
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
//在确定了拜访顺序之后,相当于再做5变最短路就好
//如果spfa,5!*5*10^5*k>10^8 可能超时
//可以先预处理,对1abcde六个点做一次单源最短路,
//可得到每个点到其他所有点的最短距离
//之后再dfs查表爆搜
//6*m+5!
//先预处理,再爆搜
#include<cstdio>
#include<queue>
typedef pair<int, int> pll;
const int N=50010, M=200010, inf=0x3f3f3f3f;
int n,m;
int h[N], e[M], w[M], ne[M], idx;
int q[N], dist[6][N];
int source[6];
bool st[N];
void add(int a, int b, int c){
e[idx]=b, w[idx]=c, ne[idx]=h[a], h[a]=idx++;
}
void dijkstra(int start, int dist[]){
memset(dist, 0x3f, N*4);
dist[start]=0;
memset(st, 0, sizeof st);
priority_queue<pll, vector<pll>, greater<pll>> heap;
heap.push({0, start});
while(heap.size()){
auto t=heap.top();
heap.pop();
int ver=t.second;
if(st[ver])continue;
st[ver]=true;
for(int i=h[ver]; ~i; i=ne[i]){
int j=e[i];
if(dist[j]>dist[ver]+w[i]){
dist[j]=dist[ver]+w[i];
heap.push({dist[j], j});
}
}
}
}
int dfs(int u, int start, int distance){
if(u>5) return distance;
int res=inf;
for(int i=1; i<=5; i++)
if(!st[i]){
int next=source[i];
st[i]=true;
res=min(res, dfs(u+1, i, distance+dist[start][next]));
st[i]=false;
}
return res;
}
int main(){
scanf("%d%d", &n,&m);
source[0]=1;
for(int i=1; i<=5; i++)scanf("%d", &source[i]);
memset(h, -1, sizeof h);
while(m--){
int a,b,c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c);
add(b, a, c);
}
for(int i=0; i<6; i++)dijkstra(source[i], dist[i]);
memset(st, 0, sizeof st);
printf("%d\n", dfs(1, 0, 0));
return 0;
}
##通信线路
https://www.acwing.com/problem/content/342/
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
#include<deque>
const int N=1010, M=20010;
int n,m,k;
int h[N], e[M], w[M], ne[M], idx;
deque<int> q;
int dist[N];
bool st[N];
void add(int a, int b, int c){
e[idx]=b, w[idx]=c, ne[idx]=h[a], h[a]=idx++;
}
bool check(int bound){
memset(st, 0, sizeof st);
memset(dist, 0x3f, sizeof dist);
dist[1]=0;
q.push_back(1);
while(q.size()){
int t=q.front();
q.pop_front();
if(st[t])continue;
st[t]=true;
for(int i=h[t]; ~i; i=ne[i]){
int j=e[i], v=w[i]>bound;
if(dist[j]>dist[t]+v){
dist[j]=dist[t]+v;
if(!v)q.push_front(j);
else q.push_back(j);
}
}
}
return dist[n]<=k;
}
int main(){
cin>>n>>m>>k;
memset(h, -1, sizeof h);
while(m--){
int a,b,c;
cin>>a>>b>>c;
add(a, b, c); add(b, a, c);
}
int l=0, r=1e6+1;
while(l<r){
int mid=l+r>>1;
if(check(mid))r=mid;
else l=mid+1;
}
if(r==1e6+1)r=-1;
cout<<r<<endl;
return 0;
}
##道路与航线
https://www.acwing.com/problem/content/344/
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
#include<algorithm>
#include<queue>
#include<vector>
#define x first
#define y second
using namespace std;
//这题spfa会被卡
//单源最短路+拓扑排序
const int N=25010, M=150010, inf=0x3f3f3f3f;
typedef pair<int, int> pii;
int n, mr, mp, S;
int h[N], e[M], w[M], ne[M], idx;
int id[N];
vector<int> block[N];
int dist[N], din[N];//距离, 入度
bool st[N];
int bcnt;
queue<int> q;
void add(int a, int b, int c){
e[idx]=b, w[idx]=c, ne[idx]=h[a], h[a]=idx++;
}
void dfs(int u, int bid){
id[u]=bid;
block[bid].push_back(u);
for(int i=h[u]; ~i; i=ne[i]){
int j=e[i];
if(!id[j])dfs(j, bid);
}
}
void dijkstra(int bid){
priority_queue<pii, vector<pii>, greater<pii>> heap;
for(auto ver: block[bid])heap.push({dist[ver], ver});
while(heap.size()){
auto t=heap.top();
heap.pop();
int ver=t.y, distance=t.x;
if(st[ver])continue;
st[ver]=true;
for(int i=h[ver]; ~i; i=ne[i]){
int j=e[i];
if(dist[j]>dist[ver]+w[i]){
dist[j]=dist[ver]+w[i];
if(id[j]==id[ver])heap.push({dist[j], j});
}
if(id[j]!=id[ver]&&--din[id[j]]==0)q.push(id[j]);
}
}
}
void topsort(){
memset(dist, 0x3f, sizeof dist);
dist[S]=0;
for(int i=1; i<=bcnt; i++)
if(!din[i])q.push(i);
while(q.size()){
int t=q.front();
q.pop();
dijkstra(t);
}
}
int main(){
scanf("%d%d%d%d", &n, &mr, &mp, &S);
memset(h, -1, sizeof h);
while(mr--){
int a,b,c;
scanf("%d%d%d", &a, &b, &c);
add(a, b, c); add(b, a, c);
}
for(int i=1; i<=n; i++)
if(!id[i])
dfs(i, ++bcnt);
while(mp--){
int a,b,c;
scanf("%d%d%d", &a, &b, &c);
add(a,b,c);
din[id[b]]++;
}
topsort();
for(int i=1; i<=n; i++)
if(dist[i]>inf/2)puts("NO PATH");
else printf("%d\n", dist[i]);
return 0;
}
##最优贸易
https://www.acwing.com/problem/content/343/
绝大多数DP可以看成是拓扑图上的最短路问题
启发:如果DP问题的依赖关系存在正环,可以通过最短路的方式求解
----c++版
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
const int N=100010, M=2000010;//无向边+反向图
int n,m;
int w[N];
int hs[N], ht[N], e[M], ne[M], idx;
int dmin[N], dmax[N];
bool st[N];
int q[N];
void add(int h[], int a, int b){
e[idx]=b, ne[idx]=h[a], h[a]=idx++;
}
void spfa(int h[], int dist[], int type){
int hh=0, tt=1;
if(type==0){
//求dmin
memset(dist, 0x3f, sizeof dmin);//sizeof 后面不能写dist,dist是一个指针
dist[1]=w[1];
q[0]=1;
}
else{
memset(dist, -0x3f, sizeof dmax);
dist[n]=w[n];
q[0]=n;
}
while(hh!=tt){
int t=q[hh++];
if(hh==N)hh=0;
st[t]=false;
for(int i=h[t]; ~i; i=ne[i]){
int j=e[i];
if(type==0 && dist[j]>min(dist[t], w[j])|| type==1&& dist[j]<max(dist[t], w[j])){
if(type==0)dist[j]=min(dist[t], w[j]);
else dist[j]=max(dist[t], w[j]);
if(!st[j]){
q[tt++]=j;//循环队列
if(tt==N)tt=0;
st[j]=true;
}
}
}
}
}
int main(){
scanf("%d%d", &n, &m);
for(int i=1; i<=n; i++)scanf("%d", &w[i]);
memset(hs, -1, sizeof hs);
memset(ht, -1, sizeof ht);
while(m--){
int a,b,c;
scanf("%d%d%d", &a, &b, &c);
add(hs, a, b), add(ht, b, a);
if(c==2)add(hs, b, a), add(ht, a, b);
}
spfa(hs, dmin, 0);
spfa(ht, dmax, 1);
int res=0;
for(int i=1; i<=n; i++) res=max(res, dmax[i]-dmin[i]);
printf("%d\n", res);
return 0;
}