您的位置:首页 > 其它

hdu1272_小希的迷宫

2011-09-27 20:32 267 查看
http://acm.hdu.edu.cn/showproblem.php?pid=1272

坑爹的题!!!

要判断图的连通性以及图是否有回路。。。要判断这两个东西都有好多方法。。

1、证明是否有回路

(1)判断 点数 = 边数 + 1 是否成立:

看到题目后好高兴,因为按照题意,如果图连通同时两点间只有一条路(不算回头路),那么这个图肯定是棵树,即 点数 = 边数 + 1 。

(证:n个独立的点为n个连通块,每加入一条边减少一个连通块,要形成一个连通块,至少要n-1条边;若图连通,则为树,在树上任意加上一条边都会形成回路,故无回路的连通图 边数 = 点数 - 1)

(2)利用顶点的度:每次把所有度为1或者0的点去掉,相关的边去掉,并把与边相关的另外的点的度都减1。不断重复这个步骤,直到图里没有度为1或0的点。

如果,此时图里没有点,则无回路;有点,则有回路。

2、剩下的就是判断图的连通性:

(1)通过一个点把所有连通的点加入,如果最后还有点没加入,则不连通。

(2)在上面利用点的度判断有否回路的过程中处理一下,就能顺便证明图是否连通的了。

(3)并查集:若所有点的根节点为同一节点,则图连通。

注意!只有一条边或者没有一个点的情况都算图连通的。

就这里坑死我了。。不断地debug,弄到最后,代码写得好恶心。。。求清爽代码。。。

代码1:

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;

const int N = 100000 + 10;
vector<int> adj
;
int d
;

int main()
{
//    freopen("in.txt", "r", stdin);
int x, y;
while (scanf("%d%d", &x, &y) != EOF && (x != -1 || y != -1))
{
//no point
if (x == 0 && y == 0)
{
printf("Yes\n");
continue;
}

memset(d, 0, sizeof(d));
for (int i = 0; i < N; i++)
adj[i].clear();
d[x]++, d[y]++;
adj[x].push_back(y);
adj[y].push_back(x);
while (scanf("%d%d", &x, &y) != EOF && (x + y))
{
d[x]++, d[y]++;
adj[x].push_back(y);
adj[y].push_back(x);
}

//判断是否无环and连通(利用无向图顶点的度)
queue<int> q;
for (int i = 1; i <= N; i++)
if (d[i] == 1)
{
q.push(i);
break;
}
while (!q.empty())
{
int tmp = q.front();
d[tmp] = -1;
q.pop();
if (adj[tmp].size() == 1)
{
int temp = adj[tmp][0];
for (int i = 0; i < adj[temp].size(); i++)
{
if (adj[temp][i] == tmp)
adj[temp].erase(adj[temp].begin() + i);
if (d[adj[temp][i]] <= 1)
q.push(adj[temp][i]);
}
d[temp]--;
if (d[temp] <= 1)
q.push(temp);
adj[tmp].clear();
}
}
int cnt = 0;
for (int i = 1; i <= N; i++)
if (d[i] > 0)
cnt++;

if (cnt == 0)
printf("Yes\n");
else printf("No\n");
}
}


代码2:

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
using namespace std;

const int N = 100000 + 10;
bool used
;
vector<int> adj
;

int main()
{
//    freopen("in.txt", "r", stdin);

int x, y;
while (scanf("%d%d", &x, &y) != EOF && (x != -1 || y != -1))
{
//no point
if (x == 0 && y == 0)
{
printf("Yes\n");
continue;
}

queue<int> q;
q.push(x);

int cnte = 0, cntp = 0;
for (int i = 0; i < N; i++)
adj[i].clear();
memset (used, 0, sizeof(used));
if (!used[x]) used[x] = 1, cntp++;
if (!used[y]) used[y] = 1, cntp++;
cnte++;
adj[x].push_back(y);
adj[y].push_back(x);
while (scanf("%d%d", &x, &y) != EOF && (x != 0 || y != 0))
{
if (!used[x]) used[x] = 1, cntp++;
if (!used[y]) used[y] = 1, cntp++;
cnte++;
adj[x].push_back(y);
adj[y].push_back(x);
}

//if the graph is connected
memset(used, 0, sizeof(used));
used[q.front()] = true;
int ans = 1;
while (!q.empty())
{
int tmp = q.front();
q.pop();
for (int i = 0; i < adj[tmp].size(); i++)
if (!used[adj[tmp][i]])
{
q.push(adj[tmp][i]);
used[adj[tmp][i]] = true;
ans++;
}
}

//如果无回路,则顶点数等于边数+1
if (cnte == cntp - 1 && ans == cntp)
printf("Yes\n");
else printf("No\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: