说是Floyd模板题,但我还是用了Dijkstra算法。
完整代码如下:
#include
using namespace std;
#define M 105
#define inf 0x7FFFFFFF
int n,m,u,v,w,Min,nex;
int Map[M][M];
int Dist[M];
bool vis[M];
int main()
{
// freopen("D:\\test.txt","r",stdin);
cin>>n>>m;
for(int i=1 ; i<=n ; i++) fill(Map[i]+1,Map[i]+1+n,inf);
// for(int j=1 ; j<=n ; j++) Map[i][j] = inf;
for(int i=0 ; i>u>>v>>w;
Map[u][v] = min(Map[u][v],w);
Map[v][u] = Map[u][v];
}
for(int s=1 ; s<=n ; s++){
// for(int a=1 ; a<=n ; a++) vis[a]=1;
fill(vis+1,vis+1+n,1);
// for(int a=1 ; a<=n ; a++) Dist[a]=inf;
fill(Dist+1,Dist+1+n,inf);
int tmp = n;
int start = s;
Dist[start]=0;
vis[start]=0;
while(--tmp){
Min = inf;
for(int i=1 ; i<=n ; i++){
if(Map[start][i]!=inf)
Dist[i]=min(Dist[i],Dist[start]+Map[start][i]);
if(vis[i] && Dist[i]
关键词:链式前向星、堆优化Dijkstra
思路:使用小根堆优化的 Dijkstra
算法(利用priority_queue)
对起始点的所有边都遍历一遍后,将成功以更近的方式到达目标点的情况记录下来,以目前从起始点到达各个终点的总距离由小到大的方式进行排序(入优先队列),其中最短的一条路径就是该终点的最短路径(数学证明略)。这样,我们每次都能确定一个点的最短距离,记录到 dij
数组里,然后再以这个点为起点(出队),遍历以它为起点的所有边(此时之前更长一些的路径还在队列里,要和它一起比较看谁更短),入队,我们就又能确定第二近的点及其总路程,如此往复,直到队列里没有点了,所有的最短路径就都找到了。
完整代码如下:
#include
using namespace std;
#define inf 0x7FFFFFFF
const int M = 2e5+5;
const int N = 1e5+5;
int n,m,s,u,v,w,nex,cnt=0;
int dij[N],head[N];
bool vis[N];
struct edge{
int to,nex,wei;
}e[M];
void add_edge(int ui, int vi, int wi)
{
e[++cnt].to = vi; // 从编号1开始记录边,不初始化head(这样默认就是0),head[i]为0说明没有边了
e[cnt].wei = wi;
e[cnt].nex = head[ui];
head[ui] = cnt;
}
struct node{
int from,wei; // 记录起点,同一起点的按wei从小到大排序,这里的wei是到这个点时总共走的路程
bool operator < (const node &x)const{ // 重载小于号,设置优先级(不要忘了大括号前的const)
return x.wei < wei;
}
}tmp;
priority_queue pq;
void dijkstra()
{
dij[s]=0;
pq.push((node){s,0});
while(!pq.empty()){
tmp = pq.top();
pq.pop();
if(vis[tmp.from]) continue;
// tmp.from为起点的点已经看过了,队列后面的都不是tmp.from的最优解,直接删掉跳过
vis[tmp.from] = true;
for(int i=head[tmp.from] ; i ; i=e[i].nex){
if(dij[e[i].to] > dij[tmp.from]+e[i].wei){
dij[e[i].to] = dij[tmp.from]+e[i].wei;
pq.push((node){e[i].to,dij[e[i].to]});
}
}
}
}
int main()
{
// freopen("D:\\test.txt","r",stdin);
cin>>n>>m>>s;
fill(dij+1,dij+1+n,inf);
for(int i=0 ; i>u>>v>>w;
add_edge(u,v,w);
}
dijkstra();
for(int i=1 ; i<=n ; i++) cout << dij[i] << " ";
return 0;
}
关键词:并查集、路径压缩
很不巧的是,我不会路径压缩,所以只能暴力求解
思路:如果两个点有公共的祖先,那么这两个点在相连后一定会形成一个环(因为每个点只会指向一个父节点),先初始化所有的点的祖先为自己,把各个点的父节点存到一个数组里,然后遍历每个点,当该点和其父节点不在同一个集合中时,将这个点的父节点设置为他的父节点;如果该点和其父节点在同一个集合中,我们从这个父节点一路向前找,一定能找到该子节点,记下路程。
本地跑不过,但是交上去能过……
完整代码如下:
#include
using namespace std;
#define inf 0x7FFFFFFF
const int N = 2e5+5;
int n,fp,cnt,fa[N],ans=inf;
int find(int k, int &cnt){
++cnt;
return k==fa[k] ? k : find(fa[k], cnt);
}
int main(){
// freopen("D:\\test.txt","r",stdin);
cin>>n;
for(int i=1 ; i<=n ; i++) fa[i]=i;
for(int i=1 ; i<=n ; i++){
cin>>fp;
cnt=0;
i==find(fp,cnt) ? ans=min(ans,cnt) : fa[i]=fp;
}
cout<
思路:使用堆优化 Dijkstra
算法,所有边的权重都是 1 1 1,开一个记录答案数量的数组 ans
,当搜到一个点时,有三种情况:路程大于先前的,直接跳过;路程等于先前的, a n s + 1 ans+1 ans+1;路程小于先前的, a n s p r e = a n s n o w ans_{pre}=ans_{now} anspre=ansnow
完整代码如下:
#include
using namespace std;
#define inf 0x7FFFFFFF
#define mod 100003
const int N = 1e6+5;
const int M = 2e6+5;
int cnt=0,n,m,ui,vi;
int head[N],ans[N],dij[N];
bool vis[N];
struct edge{
int to,nex;
}e[M];
struct node{
int from,wei;
bool operator < (const node &x)const{
return x.wei < wei;
}
}tmp;
void add_edge(int u,int v)
{
e[++cnt].to = v;
e[cnt].nex = head[u];
head[u] = cnt;
}
priority_queue pq; // 队列存起点
void dijkstra()
{
dij[1]=0;
pq.push({1,0});
while(!pq.empty()){
tmp = pq.top();
pq.pop();
if(vis[tmp.from]) continue;
vis[tmp.from] = true;
for(int i=head[tmp.from] ; i ; i=e[i].nex){
if(dij[e[i].to] > dij[tmp.from]+1){
ans[e[i].to] = ans[tmp.from];
dij[e[i].to] = dij[tmp.from]+1;
pq.push({e[i].to,dij[e[i].to]});
}
else if(dij[e[i].to] == dij[tmp.from]+1){
ans[e[i].to] += ans[tmp.from];
ans[e[i].to] %= mod;
// 这个点已经被push过了,不用再push了
}
}
}
}
int main()
{
// freopen("D:\\test.txt","r",stdin);
cin>>n>>m;
fill(dij+1,dij+1+n,inf);
ans[1]=1;
for(int i=0 ; i>ui>>vi;
add_edge(ui,vi);
add_edge(vi,ui);
}
dijkstra();
for(int i=1 ; i<=n ; i++) cout << ans[i] << '\n';
return 0;
}
思路:二分查找治理天数(注意二分的上界,实测1e7能过),要优化一下治理的过程防止超时!
完整代码如下:
#include
using namespace std;
typedef vector v;
typedef vector> vv;
#define inf 0x7FFFFFFF
const int N = 105;
int n,Q;
bool vis[N];
vv Dust(N,v(N)), Lim(N,v(N));
int dijkstra(vv DustA)
{
int nex,Min,P=0;
v dij(N);
for(int s=0 ; sQ) hdr = mid+1;
else{
mg = mid-1;
ans = mid;
}
}
return ans;
}
int main()
{
// freopen("D:\\test.txt","r",stdin);
scanf("%d%d",&n,&Q);
for(int i=0 ; i