题目大意:给你一个图,存在一个环,问所有节点到环的最短距离,节点n的个数为3000
思路:组成环的节点的度数大于等于2.。。
因为n只有3000 , 所以可以暴力求出环由哪些节点组成。具体方法就是将节点度数为1的度数减1,与他连接的节点度数减1,直至没有度数为1的节点。那么剩余度数大于等于2的节点就是组成环的节点。接下来只需要从环的每个节点dfs求出每个点的距离即可。
若数据较大时,可以采用一遍搜索确定组成环的节点。具体方法是:首先将度数为1的节点如队列,将与度数为1连接的点的度数减1,若度小于2 的节点进行如队列继续操作并标记访问。最后没有被标记访问的就是组成环的节点。。感觉这样可能跑的更快。。
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <vector>
#include <map>
#include <set>
#include <iomanip>
using namespace std;
//#pragma comment(linker, "/STACK:102400000,102400000")
#define maxn 5005
#define MOD 1000000007
#define mem(a , b) memset(a , b , sizeof(a))
#define LL long long
#define ULL unsigned long long
typedef pair<int , int> pii;
const long long INF= 0x3fffffff;
int n , m;
vector<int>v[maxn];
int d[maxn];
int vis[maxn] , vis2[maxn];
int cost[maxn];
void dfs(int root , int dis)
{
vis2[root] = 1;
cost[root] = dis;
for(int i = 0 ;i < v[root].size() ; i ++)
{
if(d[v[root][i]] >= 2|| vis2[v[root][i]]) continue;
dfs(v[root][i] , dis + 1);
}
}
int main()
{
while(scanf("%d" , &n) != EOF)
{
for(int i = 0 ; i <= n ; i ++) {v[i].clear();cost[i] = INF ;}
mem(d , 0);
mem(vis , 0);
int a , b;
for(int i = 0 ; i < n ; i ++)
{
scanf("%d %d" , &a , &b);
v[a].push_back(b);
v[b].push_back(a);
d[a]++;
d[b]++;
}
//cout << 1 << endl;
// cout << d[6] << endl;
int flag = 1;
while(flag)
{
flag = 0;
for(int i = 1 ; i <= n ; i++)
{
if(d[i] == 1)
{
// cout << i << endl;
flag = 1;
d[i]--;
for(int j = 0 ; j < v[i].size() ; j ++)
{
d[v[i][j]]--;
}
break;
}
}
}
//cout << d[6] << endl;
for(int i = 1 ; i <= n ; i ++)
{
if(d[i] >= 2) { cost[i] = 0;}
}
for(int i = 1 ; i <= n ;i ++)
{
if(d[i] >= 2)
{
mem(vis2 , 0);
dfs(i , 0);
}
}
for(int i = 1 ; i <= n ; i ++)
{
printf("%d" , cost[i]);
if(i != n) printf(" ");
}
printf("\n");
}
return 0;
}