最小生成树与最短路问题
-
最小生成树(标准算法)
#include<iostream> #include<string> #include<algorithm> using namespace std; #define ll long long #define Max 10101 struct Node { int u,v,w; bool operator<(const Node&s)const { return w<s.w; } }; int fa[Max]; int Find(int i) { if(fa[i]==i) return i; else return fa[i]=Find(fa[i]); } int main() { int n,m; while(cin>>n&&n!=0) { cin>>m; struct Node s[Max]; ll all=0; int i; for(i=1;i<=n;i++) fa[i]=i; int len=0; for(i=0;i<m;i++) cin>>s[i].u>>s[i].v>>s[i].w; sort(s,s+m); for(i=0;i<m;i++) { int u=s[i].u; int v=s[i].v; int w=s[i].w; if(Find(u)!=Find(v)) { fa[Find(u)]=fa[Find(v)]; len++; all+=w; } } cout<<all<<endl; } }
-
最小生成树(简便算法)
主要大纲: for(i=1;i<=N;i++) dis[i]=len[1][i]; //第一个到其他的联通值 x[1]=true; for(i=1;i<N;i++) { int mini=1e9+7; int k=0; for(t=1;t<=N;t++) if(x[t]==false&&mini>dis[t]) //求最小值(可以为0) (则已联通,只需求。 联通的和自己。到其他的最小值) { mini=dis[t]; k=t; } x[k]=true; all+=mini; for(t=1;t<=N;t++) if(x[t]==false&&len[k][t]<dis[t]) //更新为(联通的和自己)到其他单元的较小 联通值 { dis[t]=len[k][t]; } } cout<<all<<endl;
-
最短路算法(简便算法)
将最小生成树中 if(x[t]==false&&len[k][t]<dis[t]) { dis[t]=len[k][t]; } 改为 if(x[t]==false&&dis[k]+len[k][t]<dis[t]) { dis[t]=len[k][t]+dis[k]; }
-
最短路算法(节约内存版)(Bellman-Ford算法)
#include<bits/stdc++.h> using namespace std; #define ll long long int u[200010],v[200010],l[200010]; ll dis[20010]; int main() { int n,m; while(scanf("%d%d",&n,&m)!=EOF) { int i,t; for(i=1;i<=m;i++) scanf("%d%d%d",&u[i],&v[i],&l[i]); for(i=2;i<=n;i++) dis[i]=1e9+7; int check=0; for(i=1;i<=n;i++) { int check=0; for(t=1;t<=m;t++) if(dis[v[t]]>dis[u[t]]+l[t]) { dis[v[t]]=dis[u[t]]+l[t]; check++; } if(check==0) break; } for(i=2;i<=n;i++) cout<<dis[i]<<endl; } }
-
含负环最短路
//含有负权边的单源点最短路径 //动态规划思想:两点之间的最短路径最多经过n-1边即可到达 //那么依次更新经过1条边,2条边,...,n-1条边的最短路径 int main() { int dis[10],bak[10],i,k,n,m,u[10],v[10],w[10],check,flag; int inf=99999999; //读入n和m,n表示顶点个数,m表示边的条数 scanf("%d %d",&n,&m); //读入边 for(i=1;i<=m;i++) scanf("%d%d%d",&u[i],&v[i],&w[i]); //初始化dis数组,这里是1号顶点到其余各顶点的初始路程 for(i=1;i<=n;i++) dis[i]=inf; dis[1]=0; //Bellman-Ford算法核心语句 for(k=1;k<=n-1;k++) { //进行一轮松弛 int check=0; for(i=1;i<=m;i++) if(dis[v[i]]>dis[u[i]]+w[i]){ //这里好像将图的边看成了有向边 dis[v[i]]=dis[u[i]]+w[i]; check++; } //松弛完毕后检测dis数组是否有更新 if(check==0) break; //数组没有更新,提前退出循环算法 } //检测负权回路 flag=0; for(i=1;i<=m;i++) if(dis[v[i]]>dis[u[i]]+w[i]) flag=1; if(flag==1) printf("此图含负权回路\n"); else { for(i=1;i<=n;i++) printf("%d ",dis[i]); } return 0; }
-
树(+dfs)问题
小w不会离散数学,所以她van的图论游戏是送分的 小w有一张n个点n-1条边的无向联通图,每个点编号为1~n,每条边都有一个长度 小w现在在点x上 她想知道从点x出发经过每个点至少一次,最少需要走多少路 输入描述: 第一行两个整数 n,x,代表点数,和小w所处的位置 第二到第n行,每行三个整数 u,v,w,表示u和v之间有一条长为w的道路 输出描述: 一个数表示答案
/* 解题思路:1.原图为一棵树 2.经过每一点则经过每一条边一次或两次 3.找到x出发的最长路ans, 2*sum-ans 即为所求解 */ #include<bits/stdc++.h> using namespace std; #define ll long long struct Node { int to; ll len; Node(int a,ll b) { to=a; len=b; } }; vector<Node>g[50010]; bool dis[50010]; ll maxi=0; void dfs(int x,ll s) { dis[x]=true; int check=0; if(g[x].size()>0) { for(int i=0;i<g[x].size();i++) { int v=g[x][i].to; if(!dis[v]) { check++; dis[v]=true; dfs(v,s+g[x][i].len); dis[v]=false; } } } if(check==0) maxi=max(s,maxi); } int main() { int n,x; while(scanf("%d%d",&n,&x)!=EOF) { int i,t; int u,v; ll w; ll sum=0; for(i=1;i<n;i++) { scanf("%d%d%lld",&u,&v,&w); g[u].push_back({v,w}); g[v].push_back({u,w}); sum+=w; } memset(dis,false,sizeof(dis)); dfs(x,0); cout<<2*sum-maxi<<endl; } }
-
最短路( + bfs)问题(二维方格图)
最近,喜爱ACM的PBY同学沉迷吃鸡,无法自拔,于是又来到了熟悉的ERANGEL。经过一番搜寻,PBY同学准备动身前往安全区,但是,地图中埋伏了许多LYB,PBY的枪法很差,希望你能够帮他找到一条路线,每次只能向上、下、左、右移动,尽可能遇到较少的敌人。 输入描述: 题目包含多组测试,请处理到文件结束; 第一行是一个整数n,代表地图的大小; 接下来的n行中,每行包含n个整数a,每个数字a代表当前位置敌人的数量; 1 < n <= 100,1 <= a <= 100,-1代表当前位置,-2代表安全区。 输出描述: 对于每组测试数据,请输出从当前位置到安全区所遇到最少的敌人数量,每个输出占一行 输入 5 6 6 0 -2 3 4 2 1 2 1 2 2 8 9 7 8 1 2 1 -1 9 7 2 1 2 输出 9
/*
解题思路:1.记录每点代价
2.bfs搜索,排序,代价小的放前面
3.到达终点即退出
*/
#include<bits/stdc++.h>
using namespace std;
int ox,oy,sx,sy;
struct Node
{
int u,v;
int w;
Node(int uu,int vv,int ww)
{
u=uu; v=vv; w=ww;
}
bool operator<(const Node& a) const{
return a.w<w;
}
};
int s[110][110];
bool f[110][110];
int mx[4]={0,0,-1,1},my[4]={1,-1,0,0};
void bfs(int xo,int yo)
{
priority_queue<Node>m; //优先队列操作
m.push({xo,yo,0});
f[xo][yo]=false;
s[xo][yo]=0;
while(!m.empty())
{
Node mm=m.top();
m.pop();
for(int i=0;i<4;i++)
{
int lx=mm.u+mx[i],ly=mm.v+my[i],ls=mm.w+s[lx][ly];
if(lx==sx&&ly==sy) { printf("%d\n",ls); return; }
if(f[lx][ly])
{
m.push({lx,ly,ls});
f[lx][ly]=false;
}
}
}
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int i,t,x;
memset(f,false,sizeof(f));
for(i=1;i<=n;i++)
for(t=1;t<=n;t++)
{
scanf("%d",&x);
if(x>=0) s[i][t]=x;
else if(x==-1) { ox=i; oy=t; }
else { sx=i; sy=t; s[i][t]=0; }
f[i][t]=true;
}
bfs(ox,oy);
}
}