题目描述
Bessie and her friend Elsie decide to have a meeting. However, after Farmer John decorated his
fences they were separated into different blocks. John’s farm are divided into n blocks labelled from 1 to n.
Bessie lives in the first block while Elsie lives in the n-th one. They have a map of the farm
which shows that it takes they ti minutes to travel from a block in Ei to another block
in Ei where Ei (1≤i≤m) is a set of blocks. They want to know how soon they can meet each other
and which block should be chosen to have the meeting.
思路,优化
- 很显然的最短路,而最难的是如何去存下这个图。
- 我们使用两个表来存,一个表示一个点所对应的所有的点集,一个表示一个点集所含有的所有的结点。
- 使用dijstra算法,要深入理解其中的贪心思维,每次我们选择的时候,我们选择的是当前可扩展的距离最短的结点。而在每一个点集中移动的代价是不变的,考虑我们见过了很多次的松弛操作的方程:
Dis[S2]>Dis[S1]+W(S1,S2)
我们发现,转化的条件固定,前面的松弛初值事当前最小的,所以我们不可能再找到其他的结点使用相同的点集进行扩展可以获得更好的结果。所以每个点集只是需要扩展一次就行了。想了好久。。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>
#include<utility>
#include<queue>
using namespace std;
#define MAXN 100005
#define LL long long
#define INF 0x3f3f3f3f
vector<int>belong[MAXN];
vector<int>have[MAXN*10];
vector<int>ti;
vector<int>ansi;
int n,m,t;
int cas=0;
LL d1[MAXN],d2[MAXN];
bool used[MAXN*10];
void Init()
{
int i;
for(i=1;i<=n;i++)
belong[i].clear();
for(i=1;i<=m;i++)
have[i].clear();
ti.clear();
ti.push_back(0);
ansi.clear();
}
void MinPath(int st)
{
int i,j;
bool vis[MAXN];
priority_queue<pair<LL,int>,vector<pair<int,int> >, greater<pair<int,int> > >Q;
memset(d1,INF,sizeof(d1));
memset(vis,false,sizeof(vis));
memset(used,false,sizeof(used));
d1[st]=0;
Q.push(make_pair(0,st));
while(!Q.empty()){
LL tmplen = Q.top().first;
int tmpind = Q.top().second;
//cout << tmpind << " " << tmplen << endl;
Q.pop();
if(vis[tmpind])continue;
vis[tmpind]=true;
for(i=0;i<belong[tmpind].size();i++){
int tar = belong[tmpind][i];
//we just need a point set once
if(used[tar])continue;
used[tar]=true;
//cout << tar << endl;
for(j=0;j<have[tar].size();j++){
int dest = have[tar][j];
//cout << dest << endl;
if(!vis[dest]&&d1[dest]>tmplen+ti[tar]){
d1[dest] = tmplen + ti[tar];
Q.push(make_pair(d1[dest],dest));
}
}
}
}
return;
}
void Solve()
{
int i;
LL ans = INF;
MinPath(1);
memcpy(d2,d1,sizeof(d2));
MinPath(n);
for(i=1;i<=n;i++){
if(max(d1[i],d2[i])<ans){
ans = max(d1[i],d2[i]);
ansi.clear();
ansi.push_back(i);
}
else if(max(d1[i],d2[i])==ans)
ansi.push_back(i);
}
cas++;
printf("Case #%d: ",cas);
if(ans == INF)
printf("Evil John\n");
else{
printf("%lld\n",ans);
printf("%d",ansi[0]);
for(i=1;i<ansi.size();i++)
printf(" %d",ansi[i]);
printf("\n");
}
}
int main()
{
freopen("input","r",stdin);
int i,j;
int tmp1,tmp2,tmp3;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
Init();
for(i=1;i<=m;i++){
scanf("%d%d",&tmp1,&tmp2);
ti.push_back(tmp1);
for(j=0;j<tmp2;j++){
scanf("%d",&tmp3);
belong[tmp3].push_back(i);
have[i].push_back(tmp3);
}
}
Solve();
}
return 0;
}