ACM题集:https://blog.csdn.net/weixin_39778570/article/details/83187443
图论:https://blog.csdn.net/weixin_39778570/article/details/87825212
题目链接:http://poj.org/problem?id=1734
给定一幅无向图,求大于等于3条边的最小环的路径。
可以使用Folyd算法,枚举到第k阶段时,更新答案 ans = min(ans, d[i][j] + a[j][k] + a[k][j]),
再更新Folyd方程,表示前1~k-1个城市从i到j (j>i)的最小距离 + 从j经过k回到i,由此形成环。(只枚举不大于k的节点,由对称性可知是正确的,因为先枚举了大于k的点故中转点k小于i,j,和之后枚举i,k中转点为j是一样的,前则多次枚举i,j后达到最优,后者枚举也是,但是显然后者枚举的次数更少)
#include
#include
#include
#include
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N = 105;
int n,m,a[N][N],d[N][N],pos[N][N],ans=0x3f3f3f3f;
vector< int > Path;
void get_path(int x, int y){
if(pos[x][y]==0)return;
get_path(x, pos[x][y]);
Path.push_back(pos[x][y]);
get_path(pos[x][y], y);
}
void solve(){
memcpy(d,a,sizeof(d));
for(int k=1; k<=n; k++){
for(int i=1; i<k; i++){ // 不包含k点,作为i,j的媒介点
for(int j=i+1; j<k; j++){
// 要装换成 long long 类型!!!,3个数相加
if(ans > (ll)d[i][j]+a[j][k]+a[k][i]){// i到j溜一遍,从j经过k回到i
ans = d[i][j]+a[j][k]+a[k][i];
Path.clear();
Path.push_back(i);
get_path(i,j); // 此时i,j间还没考虑到k这个点
Path.push_back(j);
Path.push_back(k); // 最后进过的点
}
}
}
// folyd第k阶段
for(int i=1; i<=n; i++){
for(int j=1; j<=n; j++){
if(d[i][j] > d[i][k]+d[k][j]){
d[i][j] = d[i][k]+d[k][j];
pos[i][j] = k;
}
}
}
}
if(ans==0x3f3f3f3f){
puts("No solution.");
}else{
for(int i=0; i<Path.size(); i++){
printf("%d ",Path[i]);
}
puts("");
}
}
int main(){
scanf("%d%d",&n,&m);
int x,y,z;
memset(a,0x3f,sizeof(a));
fo(i,1,n)a[i][i]=0;
fo(i,1,m){
scanf("%d%d%d",&x,&y,&z);
a[x][y] = a[y][x]= min(a[x][y],z);
}
solve();
return 0;
}
题目链接:https://vijos.org/p/1423
题意:求有向图进过1的最小环
分析:直接folyd求min(d[1][i]+d[i][1]),或者建立正反图,两边Dij求1到n个点的最短路,和n个点到1的最短路。
OJ挂了,未测
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N=205, INF = 0x3f3f3f3f; // 弯道就是点
int n,m,d[N][N],t[N];
void folyd(){
fo(k,1,n)
fo(i,1,n)
fo(j,1,n)
d[i][j] = min(d[i][j], d[i][k]+d[k][j]);
int ans = INF;
fo(i,2,n)ans = min(ans, d[1][i]+d[i][1]);
if(ans == INF)puts("-1");
else printf("%d\n",ans);
}
int main(){
scanf("%d%d",&n,&m);
memset(d,0x3f, sizeof(d));
fo(i,1,n)scanf("%d",&t[i]);
int x,y,z;
fo(i,1,m){
scanf("%d%d%d",&x,&y,&z);
d[x][y] = min(d[x][y], z+t[x]);
}
folyd();
return 0;
}
#include
#define ll long long
#define fo(i,j,n) for(register int i=j; i<=n; ++i)
using namespace std;
const int N=205, M = 200005, INF = 0x3f3f3f3f; // 弯道就是点
int n,m,t[N],d[N],fd[N],g[N][N],fg[N][N];
int head[N], Next[M], ver[M], edge[M], tot;
int fhead[N], fNext[M], fver[M], fedge[M], ftot;
priority_queue<pair<int, int> > q,fq;
bool v[N];
void add(int x, int y, int z){
ver[++tot]=y, edge[tot]=z;
Next[tot]=head[x], head[x]=tot;
}
void fadd(int x, int y, int z){
fver[++ftot]=y, fedge[ftot]=z;
fNext[ftot]=fhead[x], fhead[x]=ftot;
}
void Dijkstra(int st){
memset(v, 0, sizeof(v));
memset(d, 0x3f, sizeof(d));
q.push(make_pair(0,st));
d[st]=0;
while(q.size()){
int x = q.top().second;q.pop();
if(v[x])continue;
v[x] = 1;
for(int i=head[x]; i; i=Next[i]){
int y = ver[i], wei = edge[i];
if(d[y] > d[x]+wei){
d[y] = d[x]+wei;
q.push({-d[y],y});
}
}
}
}
void fDijkstra(int st){
memset(v, 0, sizeof(v));
memset(fd, 0x3f, sizeof(fd));
fq.push(make_pair(0,st));
fd[st]=0;
while(fq.size()){
int x = fq.top().second;fq.pop();
if(v[x])continue;
v[x] = 1;
for(int i=fhead[x]; i; i=fNext[i]){
int y = fver[i], wei = fedge[i];
if(fd[y] > fd[x]+wei){
fd[y] = fd[x]+wei;
q.push({-fd[y],y});
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
memset(g,0x3f, sizeof(g));
memset(fg,0x3f, sizeof(fg));
fo(i,1,n)scanf("%d",&t[i]);
int x,y,z;
fo(i,1,m){
scanf("%d%d%d",&x,&y,&z);
g[x][y]=min(g[x][y],z+t[x]);
fg[y][x]=min(fg[y][x],z+t[x]);
}
fo(i,1,n){
fo(j,1,n){
if(g[i][j]!=INF)add(i,j,g[i][j]);
if(fg[i][j]!=INF)fadd(i,j,fg[i][j]);
}
}
Dijkstra(1);
fDijkstra(1);
int ans = INF;
fo(i,2,n)
ans = min(ans, d[i]+fd[i]);
if(ans==INF)puts("-1");
else printf("%d\n",ans);
return 0;
}