您的位置:首页 > 其它

hdu5521 Meeting

2015-11-04 20:20 302 查看

题目描述:

Meeting

Time Limit: 12000/6000 MS (Java/Others) Memory Limit: 262144/262144 K (Java/Others)

Total Submission(s): 397 Accepted Submission(s): 129

Problem Description

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.

Input

The first line contains an integer T (1≤T≤6), the number of test cases. Then T test cases

follow.

The first line of input contains n and m. 2≤n≤105. The following m lines describe the sets Ei (1≤i≤m). Each line will contain two integers ti(1≤ti≤109) and Si (Si>0) firstly. Then Si integer follows which are the labels of blocks in Ei. It is guaranteed that ∑mi=1Si≤106.

Output

For each test case, if they cannot have the meeting, then output “Evil John” (without quotes) in one line.

Otherwise, output two lines. The first line contains an integer, the time it takes for they to meet.

The second line contains the numbers of blocks where they meet. If there are multiple

optional blocks, output all of them in ascending order.

Sample Input

2

5 4

1 3 1 2 3

2 2 3 4

10 2 1 5

3 3 3 4 5

3 1

1 2 1 2

Sample Output

Case #1: 3

3 4

Case #2: Evil John

Hint

In the first case, it will take Bessie 1 minute travelling to the 3rd block, and it will take Elsie 3 minutes travelling to the 3rd block. It will take Bessie 3 minutes travelling to the 4th block, and it will take Elsie 3 minutes travelling to the 4th block. In the second case, it is impossible for them to meet.

题解:

好题.

应该想到的标准解法:

关键是边多,但是发现一个区域内部可以随便走,如果建图的话两两都要建,但是我们可以更好的建模,给每一个区域额外建一个点,然后区域内的点向这个点都连一条t/2的边.之后无脑跑迪杰斯特拉就好. 点的个数会变多一点,但是边很少,都是可以的范围内.

在赛场上的解法(后来才过的QAQ):

我们发现如果让每一个点能够被更新到的时候就能够立即被删掉.

这样每个点的均摊复杂度就是题目中给的1e6的那个上限了.

因为每个点被更新一次,o(n).但是我们不用并查集的去删,我们用一个vis来标记该区域有没有被整体更新过,保证每一个区域只更新一次,内部的点已经删过也无所谓,反正只有1e6个点.

另外每个点被更新过后,要把他能走的所有区域的二元组弄到优先队列中,这样所有的二元组也是1e6大的.但是很遗憾1e6log是跑不过去的QAQ,所以我们当前只放那个t最小的区域,然后当它出来之后我们再放小一点的,让这个优先队列尽量的小.

重点:

正解:很容易应该想到来描述一个区域内的距离的问题,就是建立一个额外的点.

sb解…:更新就能够被删掉的思维.但是看清楚这道题目并不需要删点.另外T的时候优先队列太大了.

代码:

//法二
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

typedef long long ll;

const int maxn = 1e6 + 100;
const ll INF = 1e18;

struct node1
{
int id;
node1(int _id=0)
{
id = _id;
}
};
struct node2
{
int dictid;
ll t;
node2(int _dictid=0, ll _t = 0)
{
dictid = _dictid;
t = _t;
}
};
struct node3
{
ll d, t;
int id, dictid, pos;
node3(ll _d=0,ll _t=0, int _dictid=0, int _id=0, int _pos=0)
{
d=_d;
t=_t;
dictid=_dictid;
id=_id;
pos = _pos;
}
bool operator < (const node3 b) const
{
return d+t > b.d+b.t;
}
};

vector<node1> dict[maxn];
vector<node2> elem[maxn];
int n, m;
ll dist[3][maxn], t[maxn];
int vis[maxn];

void bfs(int start, ll dist[])
{
memset(vis, 0, sizeof(vis));
for(int i = 1; i<=n; i++) dist[i] = INF;
priority_queue<node3> q;
dist[start] = 0;
if(0<elem[start].size())
{
int dictid = elem[start][0].dictid;
q.push(node3(0, elem[start][0].t, dictid, start, 0));
}
int cnt = 1;
while(cnt <= n && !q.empty())
{
node3 u = q.top();
q.pop();

ll distans = u.d+u.t;
int dictid = u.dictid, uid = u.id, upos = u.pos;

upos++;
while(upos<elem[uid].size() && vis[elem[uid][upos].dictid])
upos++;
if(upos<elem[uid].size())
q.push(node3(u.d, elem[uid][upos].t, elem[uid][upos].dictid, uid, upos));

if(vis[dictid])
continue;
vis[dictid] = 1;
for(int i = 0; i<dict[dictid].size(); i ++)
{
int v = dict[dictid][i].id;
if(dist[v]!=INF)
continue;
cnt++;
dist[v] = distans;

int j = 0;
while(j<elem[v].size()&&vis[elem[v][j].dictid])
j++;
if(j<elem[v].size())
q.push(node3(distans,elem[v][j].t, elem[v][j].dictid, v, j));
}
}
}
bool cmp(node2 a, node2 b)
{
return a.t < b.t;
}

void solve()
{
for(int i = 1; i<=m; i++)
{
dict[i].clear();
}
for(int i = 1; i<=n; i++)
{
elem[i].clear();
}
for(int i = 1; i<=m; i++)
{
int tmp;
scanf("%I64d%d", &t[i], &tmp);
for(int j = 1; j<=tmp; j++)
{
int p;
scanf("%d", &p);
dict[i].push_back(node1(p));
elem[p].push_back(node2(i));
}
}
for(int i = 1; i<=n; i++)
{
for(int j = 0; j<elem[i].size(); j++)
{
elem[i][j].t = t[elem[i][j].dictid];
}
sort(elem[i].begin(), elem[i].end(), cmp);
}

bfs(1, dist[1]);
bfs(n, dist[2]);
ll minAns = INF;
for(int i = 1; i<=n; i++)
{
if(dist[1][i]!=INF&&dist[2][i]!=INF&&max(dist[1][i],dist[2][i])<minAns)
{
minAns = max(dist[1][i],dist[2][i]);
}
}
if(minAns==INF)
{
printf("Evil John\n");
return;
}
printf("%I64d\n", minAns);
int first = 1;
for(int i = 1; i<=n; i++)
{
if(dist[1][i]!=INF&&dist[2][i]!=INF&&max(dist[1][i],dist[2][i])==minAns)
{
if(first)
{
printf("%d", i);
first = 0;
}
else
{
printf(" %d", i);
}
}
}
printf("\n");
}

int main()
{
//freopen("in.txt", "r", stdin);
int ncase;
scanf("%d", &ncase);
for(int _ = 1; _<=ncase; _++)
{
printf("Case #%d: ", _);
scanf("%d%d", &n, &m);
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: