对边bfs的最短路问题
在我们的日常做题中,我们经常会碰到一些情况,他的信息都是依照边给出的,并要求我们在这些边的基础上进行bfs以此来找出某种最短路。由于对边进行操作,我们这里就需要用到邻接表。
先行分享一个邻接表的模板
#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
int n,m,i;
const int maxmplus1=6,maxnplus1=6;
int u[maxnplus1],v[maxnplus1],w[maxnplus1];
int first[maxmplus1];
int next[maxnplus1];
scanf("%d%d",&m,&n);
fill(first,first+m,-1);
for(i=0;i<m;i++)
{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
next[i]=first[u[i]];
first[u[i]]=i;
}
}
然后就是对邻接表的这些边进行遍历了
struct node{
LL point,info;
int fa;//与前一点构成的边的标号
friend bool operator<(node a,node b)
{
return a.info>b.info;
}
};
priority_queue<node> q;
LL bfs()
{
while(!q.empty()) q.pop();
memset(flag,0,sizeof(flag));
node a={1,0,-1};
q.push(a);
while(!q.empty())
{
a=q.top();
q.pop();
if(a.point==n)
{
return a.info;
}
if(a.fa!=-1&&flag[a.fa])continue;
flag[a.fa]=1;
for(int i=first[a.point];i!=-1;i=nxt[i])
{
node b=a;
b.fa=i;
b.point=该边的下一个点;
b.info+=该边的权重;
//可以再加上一些其他操作
q.push(b);
}
}
}
大致模板就是这样了。来看两个题目
1081: 集训队分组
csuoj1081
http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1081
Description
中南大学ACM的暑期集训马上就要开始了,这次集训会将全体N名集训队员(编号分别为1, 2, …, N)按集训选拔赛的排名分成两组,前K名队员分入A组,其余队员分入B组。
但现在助理教练CSGrandeur一不小心把集训选拔赛的排名弄丢了,而之前又没将A组和B组的人员确定出来,于是CSGrandeur打算问一下集训人员他们的名次各是怎样的,以此来确定一下A组的队员。
然而集训队员们都视名次如粪土,只是隐约记得某些人排在了自己的后面,最终反馈到CSGrandeur这里的一共有M条信息,每条信息都可以用一个二元组(x, y) (x!=y)表示,含义为第x名队员记得第y名队员的排名比自己的要靠后。
现在CSGrandeur想知道,根据这M条信息,是否可以确定出A组的队员呢?(默认所有集训队员反映的信息都是符合事实的。)
Input
输入包含多组测试数据。
对于每组测试数据,第一行包含三个正整数N (2<=N<=1000)、K (1<=K<=N)、M (1<=M<=10000),含义同上。接下来M行每行有两个正整数x、y (1<=x, y<=N且x!=y),分别描述了M条信息,对于每对x、y,均表示第x名队员记得第y名队员的排名比自己的要靠后。
Output
对于每组测试数据,如果可以确定出A组的队员,输出“YES”(不包括引号),否则输出“NO”(不包括引号)。
Sample Input
3 1 2
1 2
1 3
3 2 2
1 2
1 3
Sample Output
YES
NO
Hint
Source
CSU Monthly 2012 Jun.
可以说是对边bfs最典型的模板题了,没什么好说的,直接上代码了
#include<iostream>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=1e5+5;
int first[maxn],nxt[maxn],edg[maxn][2];
inline void Add(int a,int b,int tim)
{
nxt[tim]=first[a];
first[a]=tim;
edg[tim][0]=a,edg[tim][1]=b;
}
int vis[maxn];
queue<int> q;
int bfs(int ind)
{
memset(vis,0,sizeof(vis));
while(!q.empty()) q.pop();
q.push(ind);
int cnt=0;
vis[ind]=1;
while(!q.empty())
{
int i;
int t=q.front();
q.pop();
for(i=first[t];i!=-1;i=nxt[i])
{
if(!vis[edg[i][1]])
{
cnt++;
vis[edg[i][1]]=1;
q.push(edg[i][1]);
}
}
}
return cnt;
}
int main()
{
int n,k,m;
while(~scanf("%d%d%d",&n,&k,&m))
{
memset(nxt,0,sizeof(nxt));
memset(first,-1,sizeof(first));
int i,x,y;
for(i=0;i<m;i++)
{
scanf("%d%d",&x,&y);
Add(x,y,i);
}
int cnt=0;
for(i=1;i<=n;i++)
{
if(bfs(i)>=(n-k))
{
++cnt;
}
}
if(cnt>=k) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
}
1808: 地铁
csuoj 1808
http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1808
Description
Bobo 居住在大城市 ICPCCamp。
ICPCCamp 有 n 个地铁站,用 1,2,…,n 编号。 m 段双向的地铁线路连接 n 个地铁站,其中第 i 段地铁属于 ci 号线,位于站 ai,bi 之间,往返均需要花费 ti 分钟(即从 ai 到 bi 需要 ti 分钟,从 bi 到 ai 也需要 ti 分钟)。
众所周知,换乘线路很麻烦。如果乘坐第 i 段地铁来到地铁站 s,又乘坐第 j 段地铁离开地铁站 s,那么需要额外花费 |ci-cj | 分钟。注意,换乘只能在地铁站内进行。
Bobo 想知道从地铁站 1 到地铁站 n 所需要花费的最小时间。
Input
输入包含不超过 20 组数据。
每组数据的第一行包含两个整数 n,m (2≤n≤105,1≤m≤105).
接下来 m 行的第 i 行包含四个整数 ai,bi,ci,ti (1≤ai,bi,ci≤n,1≤ti≤109).
保证存在从地铁站 1 到 n 的地铁线路(不一定直达)。
Output
对于每组数据,输出一个整数表示要求的值。
Sample Input
3 3
1 2 1 1
2 3 2 1
1 3 1 1
3 3
1 2 1 1
2 3 2 1
1 3 1 10
3 2
1 2 1 1
2 3 1 1
Sample Output
1
3
2
Hint
Source
湖南省第十二届大学生计算机程序设计竞赛
也可以看到这题就是典型的对边进行bfs,有点不同的是,他在对应的点上还需要增加权值,且所有的边都是双向通行的,所以要设立正向的一条,反向的一条。
代码:
#include<cstring>
#include<queue>
#include<iostream>
#include<cstdlib>
#include<vector>
#include<cstdio>
using namespace std;
const int maxn=100005;
typedef long long LL;
int tot,n;
int flag[200005];
int first[200005],nxt[200005];
LL u[200005],v[200005],w[200005],r[200005];
void make_edge(int from,int to,int roar,int time)
{
u[tot]=from;
v[tot]=to;
w[tot]=time;
r[tot]=roar;
nxt[tot]=first[from];
first[from]=tot++;
}
struct node{
LL point,time;
int fa;//与前一点构成的边的标号
friend bool operator<(node a,node b)
{
return a.time>b.time;
}
};
priority_queue<node> q;
LL bfs()
{
while(!q.empty()) q.pop();
memset(flag,0,sizeof(flag));
node a={1,0,-1};
q.push(a);
while(!q.empty())
{
a=q.top();
q.pop();
if(a.point==n)
{
return a.time;
}
if(a.fa!=-1&&flag[a.fa])continue;
flag[a.fa]=1;
for(int i=first[a.point];i!=-1;i=nxt[i])
{
node b=a;
b.fa=i;
b.point=v[i];
b.time+=w[i];
if(a.fa>=0)
{
b.time+=abs(r[a.fa]-r[i]);
}
q.push(b);
}
}
}
int main()
{
int m;
while(~scanf("%d%d",&n,&m))
{
memset(first,-1,sizeof(first));
memset(nxt,0,sizeof(nxt));
tot=0;
for(int i=0;i<m;i++)
{
int a,b,c,d;
scanf("%d%d%d%d",&a,&b,&c,&d);
make_edge(a,b,c,d);
make_edge(b,a,c,d);
}
printf("%lld\n",bfs());
}
}
写这边博客呢主要是因为今天又碰到了一个题目,一开始也是直接想当然地使用了邻接表加bfs但是超时了最后上网查是树链剖分,现在也是还不会,所以先把题目贴上来,题解过两天再写
B - Ch’s gift
http://acm.hdu.edu.cn/showproblem.php?pid=6162
Ch’s gift
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 2281 Accepted Submission(s): 808
Problem Description
Mr. Cui is working off-campus and he misses his girl friend very much. After a whole night tossing and turning, he decides to get to his girl friend's city and of course, with well-chosen gifts. He knows neither too low the price could a gift be since his girl friend won't like it, nor too high of it since he might consider not worth to do. So he will only buy gifts whose price is between [a,b].
There are n cities in the country and (n-1) bi-directional roads. Each city can be reached from any other city. In the ith city, there is a specialty of price ci Cui could buy as a gift. Cui buy at most 1 gift in a city. Cui starts his trip from city s and his girl friend is in city t. As mentioned above, Cui is so hurry that he will choose the quickest way to his girl friend(in other words, he won't pass a city twice) and of course, buy as many as gifts as possible. Now he wants to know, how much money does he need to prepare for all the gifts?
Input
There are multiple cases.
For each case:
The first line contains tow integers n,m(1≤n,m≤10^5), representing the number of cities and the number of situations.
The second line contains n integers c1,c2,...,cn(1≤ci≤10^9), indicating the price of city i's specialty.
Then n-1 lines follows. Each line has two integers x,y(1≤x,y≤n), meaning there is road between city x and city y.
Next m line follows. In each line there are four integers s,t,a,b(1≤s,t≤n;1≤a≤b≤10^9), which indicates start city, end city, lower bound of the price, upper bound of the price, respectively, as the exact meaning mentioned in the description above
Output
Output m space-separated integers in one line, and the ith number should be the answer to the ith situation.
Sample Input
5 3 1 2 1 3 2 1 2 2 4 3 1 2 5 4 5 1 3 1 1 1 1 3 5 2 3
Sample Output
7 1 4
Source
2017 Multi-University Training Contest - Team 9
未完待续