可以先做一遍dijskra,然后对每个点做一遍回来的dijkstra,代码很复杂,而且显然超时,如果考虑建反图只需要做两次dijkstra,因为每个点到起点的距离等价于起点到各个点的距离,而且在反图上,原来的正向边变反向边,反向边变正向边,两次dijkstra都只可能走正向边。(因为dijkstra本来就是走正向边)
需要注意建反图后,n的范围是2倍,所以需要把n的范围开大,不然会re
P1629
#include
using namespace std;
typedef long long ll;
const int N = 2e3+10,M = 2e5+10;
int h[N],w[M],e[M],ne[M],idx,dist[N];
int n,m;
bool st[N];
typedef pair<int, int> PII;
void add(int a, int b, int c) // 添加一条边a->b,边权为c
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
void dijkstra(int s)
{
dist[s] = 0;
priority_queue<PII,vector<PII>,greater<PII>>heap;
heap.push({0,s});
while(heap.size())
{
auto t = heap.top();
heap.pop();
int distance = t.first,id = t.second;
if(st[id]) continue;
st[id] = true;
for(int i = h[id];i!=-1;i= ne[i])
{
int j = e[i];
if(dist[j]>distance+w[i])
{
dist[j] = distance+w[i];
heap.push({dist[j],j});
}
}
}
}
int main()
{
memset(dist,0x3f3f3f3f,sizeof dist);
memset(h, -1, sizeof h);
memset(st, 0, sizeof st);
cin>>n>>m;
while(m--)
{
int a,b,c;
cin>>a>>b>>c;
add(a, b, c);
add(b+n,a+n,c);//小trik +n建反图,但是要
//注意N的范围
}
dijkstra(1);
ll sum = 0;
for(int i = 1;i<=n;i++)
{
sum+=dist[i];
}
memset(st, 0, sizeof st);
memset(dist,0x3f3f3f3f,sizeof dist);
dijkstra(1+n);
for(int i = 2+n;i<=n*2;i++)
{
sum+=dist[i];
}
cout<<sum;
}
这个是对于无向无权图的最短路计数,所以可以直接使用bfs遍历即可,看每个点到1的最短距离是否等于它的前个节点的最短距离+1,如果是则计数。最后输出即可。
P1144
#include
#include
#include
using namespace std;
typedef long long ll;
const ll N = 1000000+10,M = 2000000+10;
ll mod = 100003;
ll h[N], e[M], ne[M], idx,n,m;
ll dist[N],f[N],q[N];
bool st[N];
void add(ll a,ll b)
{//加边
e[idx] = b;ne[idx] = h[a];h[a] = idx++;
}
void bfs(ll u)
{
ll hh = 0,tt = -1;
q[++tt] = u;
st[u] = true;
dist[u] = 0;
f[u] = 1;
while(hh<=tt)
{
auto t = q[hh++];
for(ll i = h[t];~i;i = ne[i])
{
ll j = e[i];
if(!st[j])
{
st[j] = true;
dist[j] = dist[t]+1;
q[++tt] = j;
}
if(dist[j]==dist[t]+1)
{
f[j] = (f[j]+f[t])%mod;
}
}
}
}
int main()
{
memset(dist,0x3f3f3f3f,sizeof dist);
memset(st, 0, sizeof st);
memset(h, -1, sizeof h);
memset(f,0,sizeof f);
cin>>n>>m;
while (m -- ){
ll a,b;
cin>>a>>b;
add(a,b);
add(b,a);
}
bfs(1);
ll ans = 0;
for(ll i = 1;i<=n;i++)
{
cout<<f[i]%mod<<endl;
// ans = (ans+f[i])%mod;
}
// cout<
return 0;
}
P1828
以每个牧场为起点,都做一遍dijskra,然后定义全局变量ans,每次把ans与奶牛距离之和取min即可
AC code:
#include
#include
#include
#include
using namespace std;
#define INF 0x3f3f3f3f
typedef pair<int, int> PII;
int n,p,c;
const int N = 1010,M = 2910;
int h[N], e[M], w[M], ne[M], idx;
int dist[N];
bool st[N];
int id[N];
int ans = INF;
void add(int a,int b,int c)
{
e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx++;
}
int dijskra(int u)
{
for(int i = 1;i<=p;i++)
{
dist[i] = INF;
st[i] = false;
}
dist[u] = 0;
priority_queue<PII,vector<PII>,greater<PII>>heap;
heap.push({0,u});//编号为1,距离为0
while(heap.size())
{
auto t = heap.top();
heap.pop();
int distance = t.first,id = t.second;
if(st[id]) continue;
st[id] = true;
for(int i = h[id];~i;i = ne[i])
{
int j = e[i];
if(dist[j]>distance+w[i])
{
dist[j] = distance+w[i];
heap.push({dist[j],j});
}
}
}
int sum = 0;
for(int j = 1;j<=n;j++)
{
if(dist[id[j]]==INF) return INF;
sum+=dist[id[j]];
}
return sum;
}
int main()
{
/*对每个牧场做一次dijkstra,用ans记录最短的总距离*/
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
memset(h, -1, sizeof h);
cin>>n>>p>>c;
for(int i = 1;i<=n;i++)
cin>>id[i];//每只奶牛所在的牧场号
while(c--)
{
int a,b,w;
cin>>a>>b>>w;
add(a,b,w);
add(b,a,w);
}
for(int i = 1;i<=p;i++)
{
ans = min(ans,dijskra(i));
}
cout<<ans;
}
P1576
dijskra的变种,需要注意如何建图,找到乘积最大的边,然后100/dist[n]即可。
#include
#include
#include
#include
using namespace std;
typedef pair<double,int>PDI;
const int N = 4010,M = 2e5+10;
int h[N],e[M],ne[M],idx;
bool st[N];
double dist[N];
double w[M];
int n,m;
void add(int a,int b,double c)
{
e[idx] = b,w[idx] = (1-c*0.01),ne[idx] = h[a],h[a] = idx++;
}
void dijiskra(int start)
{
dist[start] = 1;
priority_queue<PDI,vector<PDI>,less<PDI>>heap;
heap.push({1,start});
while(heap.size())
{
auto t = heap.top();
heap.pop();
int id = t.second;
double distance = t.first;
if(st[id]) continue;
st[id] = true;
for(int i = h[id];~i;i = ne[i])
{
int j = e[i];
if(dist[j]<distance*w[i])
{
dist[j] = distance*w[i];
if(!st[j])
{
heap.push({dist[j],j});
}
}
}
}
}
int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);
// cout.tie(0);
//反向做一遍dijskra
memset(h, -1, sizeof h);
memset(dist,-0x3f3f3f3f,sizeof dist);
cin>>n>>m;
while (m -- ){
int a,b,c;
cin>>a>>b>>c;
add(a,b,c);
add(b,a,c);
}
int start,end;
cin>>end>>start;
dijiskra(start);
printf("%.8lf",100/dist[end]);
}
P5767
需要注意是有向图,且建图方式比较特别,学习stringstream的使用,另外要找到一个性质:换乘次数即为最少坐车次数-1
//本来以为是无向图,但是仔细阅读题意后,发现是有向图
//观察到数据范围小,所以可以邻接矩阵建图
#include
#include
#include
#include
#include
#include
using namespace std;
const int N = 510,M = 110;
int a[N],q[N];
int g[N][N];
int n,m;
int dist[N];
void bfs(int u)
{
memset(dist,0x3f3f3f3f,sizeof dist);
int hh = 0,tt = -1;
q[++tt] = u;
dist[1] = 0;
while(hh<=tt)
{
auto t = q[hh++];
for(int i = 1;i<=n;i++)
{
if(g[t][i]&&dist[i]>dist[t]+1)
{
dist[i] = dist[t]+1;
q[++tt] = i;
}
}
}
}
int main()
{
memset(g,0,sizeof dist);
cin>>m>>n;
string line;
getline(cin,line);
while (m--){
//建图
getline(cin,line);
stringstream ssin(line);
int cnt = 0,p;
while(ssin>>p) a[cnt++] = p;
for(int j = 0;j<cnt;j++)
{
for(int k = j+1;k<cnt;k++)
{
g[a[j]][a[k]] = 1;
}
}
}
bfs(1);
if(dist[n]==0x3f3f3f3f)
{
cout<<"NO";
}
else
{
cout<<dist[n]-1;
}
return 0;
}
P5764
先做dijskra预处理dist数组,注意这里需要开二维的dist数组,然后dfs枚举所有情况即可
#include
using namespace std;
const int N = 5e4+10,M = 2e5+10;
typedef pair<int, int> PII;
int h[N], e[M], w[M], ne[M], idx;
int dist[6][N],n,m;
bool st[N];
bool vis[N];//爆搜时用来标记状态
int a[N],ans;
#define INF 1e9
void add(int a,int b,int c)
{
e[idx] = b,w[idx] = c,ne[idx] = h[a],h[a] = idx++;
}
void dijkstra(int u,int dist[])
{
memset(dist,0x3f3f3f3f,4*N);//只memset一维'
memset(st, 0, sizeof st);
dist[u] = 0;
priority_queue<PII,vector<PII>,greater<PII>>heap;
heap.push({0,u});
while(heap.size())
{
auto t = heap.top();
heap.pop();
int id = t.second,distance = t.first;
if(st[id]) continue;
st[id] = true;
for(int i = h[id];~i;i = ne[i])
{
int j = e[i];
if(dist[j]>distance+w[i])
{
dist[j] = distance+w[i];
heap.push({dist[j],j});
}
}
}
}
int dfs(int u,int start,int distance)
{
if(u==6)
{
return distance;
}
int res = INF;
for(int i = 1;i<=5;i++)
{
if(!vis[i])
{
int next = a[i];
vis[i] = true;
res = min(res,dfs(u+1,i,distance+dist[start][next]));
vis[i] = false;
}
}
return res;
}
int main()
{
memset(h, -1, sizeof h);
cin>>n>>m;
a[0] = 1;
for(int i = 1;i<=5;i++)
{
cin>>a[i];
}
while (m -- ){
int a,b,c;
cin>>a>>b>>c;
add(a, b, c);
add(b, a, c);
}
for(int i = 0;i<6;i++)
dijkstra(a[i],dist[i]);//先做dijskra预处理dist数组
cout<<dfs(1,0,0);
}