#define fzhead EDGE(int _from,int _to,int _w,int _next)
#define fzbody from(_from),to(_to),w(_w),next(_next)
using namespace std;
const int maxn=1e5+10;
int head[maxn],edgecount;
struct EDGE
{
int from,to,w,next;
/*
Edge(){}是个用来给变量初始化0的函数
fzhead:fzbody{}为结构体赋初值
*/
EDGE(){}//后面别加分号
fzhead:fzbody{}//后面别加分号
}edge[maxn];
void init()
{
memset(head,-1,sizeof(head));
edgecount=-1;
}
/*
i:边的编号;从u到v;w:权值;next:下一条边的编号
head[i]:由i出发的第一条边的编号
仅插入一条从u1开始的边,则next是-1,head[u1]为该边的编号
再读入u1开始的边,则其为第一条边,next是上一条边的编号
*/
void addEdge(int from,int to,int w)//链序和读入顺序相反
{
edge[++edgecount]=EDGE(from,to,w,head[from]);
head[from]=edgecount;
}
#define fzhead EDGE(int _to,int _w)
#define fzbody to(_to),w(_w)
using namespace std;
const int maxn=1e5+10;
int n;
struct EDGE
{
int to,w;
/*
Edge(){}是个用来给变量初始化0的函数
fzhead:fzbody{}为结构体赋初值
*/
EDGE(){}//后面别加分号
fzhead:fzbody{}//后面别加分号
};
vector<EDGE> edge[maxn];
void init()
{
for(int i=1;i<=n;++i) edge[i].clear();
}
/*
i:边的编号;从u到v;w:权值;next:下一条边的编号
head[i]:由i出发的第一条边的编号
仅插入一条从u1开始的边,则next是-1,head[u1]为该边的编号
再读入u1开始的边,则其为第一条边,next是上一条边的编号
*/
void addEdge(int from,int to,int w)//链序和读入顺序相反
{
edge[from].push_back(EDGE(to,w));
}
**以链式前向星存储为例**
void DFS(int root)//传入根结点序号
{
num[root]=1;
vis[root]=true;
for(int i=head[root];i!=-1;i=edge[i].next)
{
if(vis[edge[i].to]==true) continue;//如果子结点已被访问则跳过(防无向图)
DFS(edge[i].to);
}
}
**以链式前向星存储为例**
void BFS(int u)//传入根结点序号
{
Max=0;
memset(vis,0,sizeof(vis));
queue<int> Q;
Q.push(u);
vis[u]=true;
while(!Q.empty())
{
int root=Q.front();
Q.pop();
for(int i=head[root];i!=-1;i=edge[i].next)
{
if(vis[edge[i].to]==true) continue;//如果子结点已被访问则跳过(防无向图)
Q.push(edge[i].to);
vis[edge[i].to]=true;
}
}
}
int get_barycenter(int root,int dady)
{
size[root]=1;//记录一棵子树的结点数(一棵子树的大小),root作根结点初始大小为1
Max[root]=0;
for(int i=head[root];i!=-1;i=edge[i].next)
{
if (edge[i].to!=dady)
{
get_barycenter(edge[i].to,root);//递归,从叶子结点大小为 1 开始回推赋值
size[root]+=size[edge[i].to];//结点数累加,对root根结点而言的
Max[root]=max(Max[root],size[edge[i].to]);//对root子树而言的
//对于树上的每一个root,计算其所有子树中最大的子树结点数
}
}
Max[root]=max(Max[root],n-size[root]);
/*
n为总结点数,定义中的**子树**指无根树的子树
size[edge[i].to]是向下的;n-size[root]是向上的
减去自身这整棵树的结点数,剩下的就是向上的子树的结点数啦
用向下的最大值,与向上的比较得到最终的最大值
*/
if (center==0||Max[root]<Max[center]) center=root;
//center初始化为0,还未被更新过值或得到更小的最大子树结点数,就用当前root更新重心center
return center;//center为重心编号
}
Description
After Farmer John realized that Bessie had installed a “tree-shaped” network among his N (1 <= N <= 10,000) barns at an incredible cost, he sued Bessie to mitigate his losses.
Bessie, feeling vindictive, decided to sabotage Farmer John’s network by cutting power to one of the barns (thereby disrupting all the connections involving that barn). When Bessie does this, it breaks the network into smaller pieces, each of which retains full connectivity within itself. In order to be as disruptive as possible, Bessie wants to make sure that each of these pieces connects together no more than half the barns on FJ.
Please help Bessie determine all of the barns that would be suitable to disconnect.
Input
- Line 1: A single integer, N. The barns are numbered 1…N.
- Lines 2…N: Each line contains two integers X and Y and represents a connection between barns X and Y.
Output
- Lines 1…?: Each line contains a single integer, the number (from 1…N) of a barn whose removal splits the network into pieces each having at most half the original number of barns. Output the barns in increasing numerical order. If there are no suitable barns, the output should be a single line containing the word “NONE”.
Sample Input
10
1 2
2 3
3 4
4 5
6 7
7 8
8 9
9 10
3 8
Sample Output
3
8
Hint
INPUT DETAILS:
The set of connections in the input describes a “tree”: it connects all the barns together and contains no cycles.
OUTPUT DETAILS:
If barn 3 or barn 8 is removed, then the remaining network will have one piece consisting of 5 barns and two pieces containing 2 barns. If any other barn is removed then at least one of the remaining pieces has size at least 6 (which is more than half of the original number of barns, 5).
#include
#include
#include
#include
#include
#define fzhead EDGE(int _from,int _to,int _next)
#define fzbody from(_from),to(_to),next(_next)
using namespace std;
const int maxn=1e5+10;
int head[maxn],edgecount,n,num[maxn];
bool vis[maxn];
vector<int> ans;
void init()
{
memset(vis,false,sizeof(vis));
memset(head,-1,sizeof(head));
memset(num,0,sizeof(num));
edgecount=-1;
ans.clear();
}
/*
i:边的编号;从u到v;w:权值;next:下一条边的编号
head[i]:由i出发的第一条边的编号
仅插入一条从u1开始的边,则next是-1,head[u1]为该边的编号
再读入u1开始的边,则其为第一条边,next是上一条边的编号
*/
struct EDGE
{
int from,to,next;
/*
Edge(){}是个用来给变量初始化0的函数
fzhead:fzbody{}为结构体赋初值
*/
EDGE(){}//后面别加分号
fzhead:fzbody{}//后面别加分号
}edge[maxn];
/*
i:边的编号;从from到to;w:权值,此处已删除;next:下一条边的编号
head[i]:由i出发的第一条边的编号
仅插入一条从u1开始的边,则next是-1,head[u1]为该边的编号
再读入u1开始的边,则其为第一条边,next是上一条边的编号
*/
void addEdge(int from,int to)//链序和读入顺序相反
{
edge[++edgecount]=EDGE(from,to,head[from]);
head[from]=edgecount;
}
void DFS(int root)
{
num[root]=1;
vis[root]=true;
int flag=1;
for(int i=head[root];i!=-1;i=edge[i].next)
{
if(vis[edge[i].to]==true) continue;
DFS(edge[i].to);
num[root]+=num[edge[i].to];
if(num[edge[i].to]>n/2) flag=0;
//root删除后,它的每个子结点牵着一棵树
}
if(n-num[root]<=n/2&&flag) ans.push_back(root);
/*
删除root结点后,其牵着的整个子树拿走,剩余结点满足条件
且它的子树们,各自都满足条件
*/
}
int main()
{
while(~scanf("%d",&n))
{
init();
int from,to;
for(int i=1;i<n;++i)
{
scanf("%d %d",&from,&to);
addEdge(from,to);
addEdge(to,from);
}
DFS(1);
if(ans.empty()) scanf("NONE\n");
else
{
sort(ans.begin(),ans.end());
for(int i=0;i<ans.size();++i) printf("%d\n",ans[i]);
}
}
return 0;
}
int BFS(int u)//传入根结点
{
Max=0;
memset(dis,0,sizeof(dis));//距离数组
memset(vis,0,sizeof(vis));//访问标记
queue<int> Q;
Q.push(u);
vis[u]=true;
int to=u;
while(!Q.empty())
{
int root=Q.front();
Q.pop();
used[root]=true;
for(int i=head[root];i!=-1;i=edge[i].next)
{
if(!vis[edge[i].to])//如果子结点已被访问则跳过(防无向图)
{
dis[edge[i].to]=dis[root]+edge[i].w;//从上往下累加总路程
if(dis[edge[i].to]>Max)//某一次比Max大的时候
{
Max=dis[edge[i].to];
to=edge[i].to;//用to标记Max最大时的终点
}
Q.push(edge[i].to);//从Max最大的终点继续BFS,若无更大的Max则队列为空return to;
vis[edge[i].to]=true;
}
}
}
return to;//返回的是从传入的根节点开始,最长路径的终点
}
**然后在int main()主函数中调用两次BFS函数**
int start=BFS(1);//第一次随便指定根结点
BFS(start);//第二次从返回的to(赋值给了start)开始(start为根结点,也是直径的一端)
Description
随着杭州西湖的知名度的进一步提升,园林规划专家湫湫希望设计出一条新的经典观光线路,根据老板马小腾的指示,新的风景线最好能建成环形,如果没有条件建成环形,那就建的越长越好。
现在已经勘探确定了n个位置可以用来建设,在它们之间也勘探确定了m条可以设计的路线以及他们的长度。请问是否能够建成环形的风景线?如果不能,风景线最长能够达到多少?
其中,可以兴建的路线均是双向的,他们之间的长度均大于0。
Input
测试数据有多组,每组测试数据的第一行有两个数字n, m,其含义参见题目描述;
接下去m行,每行3个数字u v w,分别代表这条线路的起点,终点和长度。
[Technical Specification]
1. n<=100000
2. m <= 1000000
3. 1<= u, v <= n
4. w <= 1000
Output
对于每组测试数据,如果能够建成环形(并不需要连接上去全部的风景点),那么输出YES,否则输出最长的长度,每组数据输出一行。
Sample Input
3 3
1 2 1
2 3 1
3 1 1
Sample Output
YES
#include
#include
#include
#include
#include
#define fzhead EDGE(int _from,int _to,int _w,int _next)
#define fzbody from(_from),to(_to),w(_w),next(_next)
using namespace std;
const int maxn = 1e5+10;
int father[maxn],head[maxn],dis[maxn],edgecount,Max,n,m;
bool vis[maxn],used[maxn],tag;
void init()
{
for(int i=1;i<=n;++i) vis[i]=false,father[i]=i;
memset(head,-1,sizeof(head));
memset(used,0,sizeof(used));
memset(dis,0,sizeof(dis));
edgecount=-1;
}
/*
i:边的编号;从u到v;w:权值;next:下一条边的编号
head[i]:由i出发的第一条边的编号
仅插入一条从u1开始的边,则next是-1,head[u1]为该边的编号
再读入u1开始的边,则其为第一条边,next是上一条边的编号
*/
struct EDGE
{
int from,to,w,next;
/*
Edge(){}是个用来给变量初始化0的函数
fzhead:fzbody{}为结构体赋初值
*/
EDGE(){}//后面别加分号
fzhead:fzbody{}//后面别加分号
}edge[maxn*20];
/*
i:边的编号;从from到to;w:权值,此处已删除;next:下一条边的编号
head[i]:由i出发的第一条边的编号
仅插入一条从u1开始的边,则next是-1,head[u1]为该边的编号
再读入u1开始的边,则其为第一条边,next是上一条边的编号
*/
void addEdge(int from,int to,int w)//链序和读入顺序相反
{
edge[++edgecount]=EDGE(from,to,w,head[from]);
head[from]=edgecount;
}
int find(int x){return x==father[x]?x:father[x]=find(father[x]);}
bool baba(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx==fy) return true;
else
{
father[fx]=fy;
return false;
}
}
int BFS(int u)
{
Max=0;
memset(dis,0,sizeof(dis));
memset(vis,0,sizeof(vis));
queue<int> Q;
Q.push(u);
vis[u]=true;
int to=u;
while(!Q.empty())
{
int root=Q.front();
Q.pop();
used[root]=true;
for(int i=head[root];i!=-1;i=edge[i].next)
{
if(!vis[edge[i].to])//如果子结点已被访问则跳过(防无向图)
{
dis[edge[i].to]=dis[root]+edge[i].w;//从上往下累加总路程
if(dis[edge[i].to]>Max)//某一次比Max大的时候
{
Max=dis[edge[i].to];
to=edge[i].to;//用to标记Max最大时的终点
}
Q.push(edge[i].to);//从Max最大的终点处继续BFS,若无更大的Max了则队列为空
vis[edge[i].to]=true;
}
}
}
return to;//返回的是从传入的根节点开始,最长风景线的终点
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
init();
tag=false;
for(int i=1;i<=m;i++)
{
int u,v,w;
scanf("%d %d %d",&u,&v,&w);
if(tag) continue;
if(baba(u,v)) tag=true;
//输出的同时处理是否成环,若已成环,无需再加边,后续直接输出YES
addEdge(u,v,w);
addEdge(v,u,w);
}
if(tag)//已成环
{
printf("YES\n");
continue;//跳过后续步骤,直接下一次输入
}
int ans=-1;//用于比较得到最长风景线
for(int i=1;i<=n;i++)
{
if(!used[i])
{
int start=BFS(i);
/*
从未被标记参与过最长风景线诞生的某点开始BFS
找到最长风景线的其中一端
然后再继续BFS找到另一端得到这一遍最后的Max
所有没有标记参与最长风景线诞生的点都遍历一次,找最大的Max
注意此题可能不止一棵树,一个未标记,就可能有一棵新的树
***所以此时是在找不同树之间的最大直径!!!***
*/
BFS(start);
ans=max(ans,Max);
}
}
printf("%d\n",ans);
}
return 0;
}
Description
There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure of employees. It means that the supervisor relation forms a tree rooted at the rector V. E. Tretyakov. In order to make the party funny for every one, the rector does not want both an employee and his or her immediate supervisor to be present. The personnel office has evaluated conviviality of each employee, so everyone has some number (rating) attached to him or her. Your task is to make a list of guests with the maximal possible sum of guests’ conviviality ratings.
Input
Employees are numbered from 1 to N. A first line of input contains a number N. 1 <= N <= 6 000. Each of the subsequent N lines contains the conviviality rating of the corresponding employee. Conviviality rating is an integer number in a range from -128 to 127. After that go T lines that describe a supervisor relation tree. Each line of the tree specification has the form:
L K
It means that the K-th employee is an immediate supervisor of the L-th employee. Input is ended with the line
0 0
Output
Output should contain the maximal sum of guests’ ratings.
Sample Input
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
Sample Output
5
#include
#include
#include
#include
#include
#define fzhead EDGE(int _from,int _to,int _next)
#define fzbody from(_from),to(_to),next(_next)
using namespace std;
const int maxn=2e5+10;
int head[maxn],edgecount,dp[maxn][2],n,ans;
bool vis[maxn];//DFS中标记是否已被访问
void init()
{
memset(head,-1,sizeof(head));
memset(vis,false,sizeof(vis));
edgecount=-1;
}
/*
i:边的编号;从u到v;w:权值;next:下一条边的编号
head[i]:由i出发的第一条边的编号
仅插入一条从u1开始的边,则next是-1,head[u1]为该边的编号
再读入u1开始的边,则其为第一条边,next是上一条边的编号
*/
struct EDGE
{
int from,to,next;
/*
Edge(){}是个用来给变量初始化0的函数
fzhead:fzbody{}为结构体赋初值
*/
EDGE(){}//后面别加分号
fzhead:fzbody{}//后面别加分号
}edge[maxn];
/*
i:边的编号;从from到to;w:权值,此处已删除;next:下一条边的编号
head[i]:由i出发的第一条边的编号
仅插入一条从u1开始的边,则next是-1,head[u1]为该边的编号
再读入u1开始的边,则其为第一条边,next是上一条边的编号
*/
void addEdge(int from,int to)//链序和读入顺序相反
{
edge[++edgecount]=EDGE(from,to,head[from]);
head[from]=edgecount;
}
void DFS(int root)
{
vis[root]=true;
for(int i=head[root];i!=-1;i=edge[i].next)
{
if(vis[edge[i].to]==true) continue;//如果子结点已被访问则跳过(防无向图)
DFS(edge[i].to);//未被访问则递归到叶子结点
dp[root][0]+=max(dp[edge[i].to][0],dp[edge[i].to][1]);
/*
DP思路(状态转移方程思路):
此根结点若不选,则它的子结点可选可不选
此根结点若选,则它的子结点不可选
递归出口是叶子节点,然后逆着返回
*/
dp[root][1]+=max(0,dp[edge[i].to][0]);
}
}
int main()
{
while(~scanf("%d",&n))
{
init();
for(int i=1;i<=n;++i)
{
scanf("%d",&dp[i][1]);
dp[i][0]=0;
}
int to,from;
while(~scanf("%d %d",&to,&from)&&to+from)
{
addEdge(to,from);
addEdge(from,to);
}
DFS(1);//传入根结点
printf("%d\n",max(dp[1][0],dp[1][1]));//输出根结点选或不选的最大值
}
return 0;
}
Description
A school bought the first computer some time ago(so this computer’s id is 1). During the recent years the school bought N-1 new computers. Each new computer was connected to one of settled earlier. Managers of school are anxious about slow functioning of the net and want to know the maximum distance Si for which i-th computer needs to send signal (i.e. length of cable to the most distant computer). You need to provide this information.
Hint: the example input is corresponding to this graph. And from the graph, you can see that the computer 4 is farthest one from 1, so S1 = 3. Computer 4 and 5 are the farthest ones from 2, so S2 = 2. Computer 5 is the farthest one from 3, so S3 = 3. we also get S4 = 4, S5 = 4.
Input
Input file contains multiple test cases.In each case there is natural number N (N<=10000) in the first line, followed by (N-1) lines with descriptions of computers. i-th line contains two natural numbers - number of computer, to which i-th computer is connected and length of cable used for connection. Total length of cable does not exceed 10^9. Numbers in lines of input are separated by a space.
Output
For each case output N lines. i-th line must contain number Si for i-th computer (1<=i<=N).
Sample Input
5
1 1
2 1
3 1
1 1
Sample Output
3
2
3
4
4
**它涉及无根树非假定的根结点到其他节点的最远距离**
**考虑向上和向下的两种子树,并非树的直径类型题**
#include
#include
#include
#include
#include
#define fzhead EDGE(int _from,int _to,int _w,int _next)
#define fzbody from(_from),to(_to),w(_w),next(_next)
using namespace std;
const int maxn=1e5+10;
int head[maxn],edgecount,dp[maxn][3],n,test;
/*
dp[i][0]为从下往上的最远距离
dp[i][1]为从下往上的次远距离
dp[i][2]为从经过root的最远距离
*/
bool vis[maxn];
void init()
{
memset(vis,false,sizeof(vis));
memset(head,-1,sizeof(head));
memset(dp,0,sizeof(dp));
edgecount=-1;
}
/*
i:边的编号;从u到v;w:权值;next:下一条边的编号
head[i]:由i出发的第一条边的编号
仅插入一条从u1开始的边,则next是-1,head[u1]为该边的编号
再读入u1开始的边,则其为第一条边,next是上一条边的编号
*/
struct EDGE
{
int from,to,w,next;
/*
Edge(){}是个用来给变量初始化0的函数
fzhead:fzbody{}为结构体赋初值
*/
EDGE(){}//后面别加分号
fzhead:fzbody{}//后面别加分号
}edge[maxn];
/*
i:边的编号;从from到to;w:权值,此处已删除;next:下一条边的编号
head[i]:由i出发的第一条边的编号
仅插入一条从u1开始的边,则next是-1,head[u1]为该边的编号
再读入u1开始的边,则其为第一条边,next是上一条边的编号
*/
void addEdge(int from,int to,int w)//链序和读入顺序相反
{
edge[++edgecount]=EDGE(from,to,w,head[from]);
head[from]=edgecount;
}
void DFS1(int root)//深搜从下往上的最远和次远距离
{
int first=0,second=0;//first最远,second次远
//不可定义为全局变量,不然递归内部更改的同时外部也在更改,应当各自独立记录
vis[root]=true;
for(int i=head[root];i!=-1;i=edge[i].next)
{
if(vis[edge[i].to]==true) continue;//如果子结点已被访问则跳过(防无向图)
DFS1(edge[i].to);
test=dp[edge[i].to][0]+edge[i].w;
//这一轮用于比较的test是已经从下往上形成的最远距离+此距离
if(test>=first)//更新最远(原最远变次远)
{
second=first;
first=test;
}
else if(test>second) second=test;//更新次远
}
dp[root][0]=first;//root结点从下往上的最远距离
dp[root][1]=second;//root结点从下往上的次远距离
}
void DFS2(int root)//求子结点们经过父结点的最远距离
{
vis[root]=true;
for(int i=head[root];i!=-1;i=edge[i].next)
{
if(vis[edge[i].to]==true) continue;//如果子结点已被访问则跳过(防无向图)
if(dp[edge[i].to][0]+edge[i].w==dp[root][0])
dp[edge[i].to][2]=max(dp[root][2],dp[root][1])+edge[i].w;
else
dp[edge[i].to][2]=max(dp[root][2],dp[root][0])+edge[i].w;
/*
遍历到父结点(root),求其子结点们经过父结点的最远距离
1.根结点经过其父结点过来的的最远距离
2.子结点从下往上的最远距离+此距离 判断是否等于 现根结点(root)从下往上的最远距离
3.在 2 中,相等的话 返回根结点(root)从下往上的次远距离
4.在 2 中,不相等的话 返回根结点(root)从下往上的最远距离+此距离
5.求出前两者的最大值,加上这次的权值即可
*/
/*
因为要比较从上往下和从下往上哪个更远,所以两者的值得不同
然后再用父结点向上或向下的最大值,加上现在的值,得到新值
如果if条件满足,依旧用dp[root][0]进行比较的话
相当于root结点从下往上的最大值经过了现在要求的这个子结点
等于1-2-3这条链,想求2的最远路,走的却是3-2-1-2,有重合段了
所以对于父结点从下往上的最远距离,必须保证不经过现在的这个子结点
如果最大值经过,那么就用次大值进行比较
再加上从父结点走向子结点的路程,得到子结点的新值
*/
DFS2(edge[i].to);//最后递归,因为计算表达式用到父结点,得顺着传值
}
}
int main()
{
while(~scanf("%d",&n))
{
init();
int from,value;
for(int i=2;i<=n;++i)
{
scanf("%d %d",&from,&value);
addEdge(from,i,value);
}
DFS1(1);//传入根结点序号
dp[1][2]=0;//初始化根结点经过其父结点过来的最远距离为0
memset(vis,false,sizeof(vis));//初始化均未被访问过
DFS2(1);//传入根结点序号
for(int i=1;i<=n;++i) printf("%d\n",max(dp[i][0],dp[i][2]));
//一个结点的最远距离要么是往下走,要么是往上走经过根结点的
}
return 0;
}