您的位置:首页 > 理论基础 > 数据结构算法

Sparse Graph(2016大连网赛)(hdu5876)(BFS+数据结构)

2016-09-11 17:56 225 查看
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5876

题意:给一个起点和一个原图,问从起点到原图补图(原图中连着的点在补图中不连,不连的点在补图中连)的每个点的最短距离。每条边的长度都是1.

题解:由于每条边的长度都是1,所以可以用BFS,从起点开始一层一层BFS。可是由于要在补图上跑,所以要反向思考一下,把所有与当前搜索到节点连着的点都从这个点所能到达集合里面去掉。而且这道题的数据量有点大,时间复杂度有点坑,如果每一次都遍历所有的点的话,会惨烈的超时。

所以用了两个集合。

一个集合s1初始时是所有还没有被搜索到的点,即将要存储现在所有没有到达但这一次BFS可以到达的点。一个集合s2存储现在还没有到达的,且这一次BFS不能到达的点。

如果u在原图中可以到达点v,那么在补图中就不能到达点v,所以就要把v加入s2,并在s1中除去。

s1、s2更新的时候就已经把原来到达过的点去掉了,所以时间复杂度一下子就下来了,也就是一个元素,如果已经被搜索过了,那么将不会参加后续操作,时间复杂度一下子就下来了。(好神奇)

思考:

1、用数据结构优化代码复杂度

2、做题太少,知道的姿势太少

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <set>
#include <queue>
#include <iterator>

using namespace std;

const int maxn = 200010 * 5;
const int maxm = 20010;
int cnt;
int n, m, s;
int head[maxn];
int d[maxn];

struct Edge{
int v, next, c;
}edge[maxn];

void addedge(int u, int v, int c)
{
edge[cnt].v = v;
edge[cnt].c = c;
edge[cnt].next = head[u];
head[u] = cnt++;
}

void init()
{
cnt = 0;
memset (head, -1, sizeof(head));
memset (d, -1, sizeof(d));
}

void BFS()
{
set<int> s1;
set<int> s2;
for (int i = 1; i <= n; i++) {
s1.insert(i);
}
d[s] = 0;
s1.erase(s);
queue<int> q;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = head[u]; i != -1; i = edge[i].next) {
int v= edge[i].v;
if (!s1.count(v)) continue;
s1.erase(v);
s2.insert(v);
}
for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) {
q.push(*it);
d[*it] = d[u] + 1;
}
s1.swap(s2);
s2.clear();
}
}

int main()
{
int t;
scanf ("%d", &t);
while (t--) {
scanf ("%d%d", &n, &m);
init ();
for (int i = 0; i < m; i++) {
int u, v;
scanf ("%d%d", &u, &v);
addedge (u, v, 1);
addedge (v, u, 1);
}
scanf ("%d", &s);
BFS ();
if (s == 1) {
printf ("%d", d[2]);
for (int i = 3; i <= n; i++) {
printf (" %d", d[i]);
}
} else {
printf ("%d", d[1]);
for (int i = 2; i <= n; i++) {
if (i == s) continue;
printf (" %d", d[i]);
}
}
printf ("\n");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: