codeforces 734e(连通分量缩点)
2017-10-23 13:45
357 查看
E. Anton and Tree
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Anton is growing a tree in his garden. In case you forgot, the tree is a connected acyclic undirected graph.
There are n vertices in the tree, each of them is painted black or white. Anton doesn't like multicolored trees, so he wants to change
the tree such that all vertices have the same color (black or white).
To change the colors Anton can use only operations of one type. We denote it as paint(v), where v is
some vertex of the tree. This operation changes the color of all vertices u such that all vertices on the shortest path from v to u have
the same color (including v andu).
For example, consider the tree
and apply operation paint(3) to get the following:
Anton is interested in the minimum number of operation he needs to perform in order to make the colors of all vertices equal.
Input
The first line of the input contains a single integer n (1 ≤ n ≤ 200 000) —
the number of vertices in the tree.
The second line contains n integers colori (0 ≤ colori ≤ 1) —
colors of the vertices. colori = 0 means
that the i-th vertex is initially painted white, while colori = 1 means
it's initially painted black.
Then follow n - 1 line, each of them contains a pair of integers ui and vi (1 ≤ ui, vi ≤ n, ui ≠ vi) —
indices of vertices connected by the corresponding edge. It's guaranteed that all pairs (ui, vi) are
distinct, i.e. there are no multiple edges.
Output
Print one integer — the minimum number of operations Anton has to apply in order to make all vertices of the tree black or all vertices of the tree white.
Examples
input
output
input
output
题意:包含n个点的一棵树,每个点都有黑白两种颜色,每改变一个节点的颜色,他周围和它颜色相同的节点也变色(一整块颜色相同的点),求让这棵树变成同一种颜色的最小操作。
思路:利用连通量缩点,重新建图,求出最远两个节点的距离x,(x+1)/2就是答案
看了别人题解用模板写了个很挫的代码。。。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
#define MAX_V 200005
int V;
int ans;
vector<int>G[MAX_V]; //原图
vector<int>rG[MAX_V]; //反向边图
vector<int>gc[MAX_V]; //缩点之后的图
vector<int>vs; //后序遍历顶点序列
bool used[MAX_V]; //访问标记
int cmp[MAX_V]; //所属强连通分量拓扑序
bool color[MAX_V]; //颜色
int dp[MAX_V]; //记录每个点到其他所有点中最远点的距离
void add_edge(int from,int to)
{
G[from].push_back(to);
rG[to].push_back(from);
}
void dfs(int v) //第一次dfs
{
used[v]=true;
for(int i=0;i<G[v].size();i++)
{
if(!used[G[v][i]])dfs(G[v][i]);
}
vs.push_back(v);
}
void rdfs(int v,int k) //第二次dfs
{
used[v]=true;
cmp[v]=k;
for(int i=0;i<rG[v].size();i++)
{
if(!used[rG[v][i]])rdfs(rG[v][i],k);
}
}
int scc()
{
memset(used,0,sizeof(used));
vs.clear();
for(int v=0;v<V;v++)
{
if(!used[v])dfs(v);
}
memset(used,0,sizeof(used));
int k=0;
for(int i=vs.size()-1;i>=0;i--)
{
if(!used[vs[i]])
{
rdfs(vs[i],k++);
}
}
return k;
}
void DFS(int u,int fa)
{
int mx=0,mmx=0;//mx是点到图的任意一点的最远距离,mmx是次远距离
for(int i=0;i<gc[u].size();i++)
{
int v=gc[u][i];
if(v==fa) continue;//防止遍历回父节点
DFS(v,u);
mmx=max(mmx,dp[v]+1);
if(mmx>mx) swap(mmx,mx);
}
dp[u]=mx;
ans=max(ans,mx+mmx);//图的直径等于某个点的最远距离加上次远距离
}
void init()
{
ans=0;
for(int i=0;i<MAX_V;i++)
{
G[i].clear();
rG[i].clear();
gc[i].clear();
}
vs.clear();
memset(used,0,sizeof(used));
memset(cmp,0,sizeof(cmp));
memset(color,0,sizeof(color));
memset(dp,0,sizeof(dp));
}
int main()
{
while(~scanf("%d",&V))
{
for(int i=0;i<V;i++)scanf("%d",&color[i]);
int f,t;
for(int i=0;i<V-1;i++)
{
scanf("%d%d",&f,&t);
if(color[f-1]==color[t-1]) //如果两点颜色一样就是无向边,颜色不一样就是有向边
{
add_edge(f-1,t-1);
add_edge(t-1,f-1);
}
else add_edge(f-1,t-1);
}
int h=scc();
//重新建图
for(int i=0;i<V;i++)
{
for(int j=0;j<G[i].size();j++)
{
int v=G[i][j];
if(cmp[v]!=cmp[i])
{
gc[cmp[v]].push_back(cmp[i]);
gc[cmp[i]].push_back(cmp[v]);
}
}
}
DFS(0,-1);
printf("%d\n",(ans+1)/2);
}
}下面是别人的代码:http://blog.csdn.net/pan1197349032/article/details/53217462
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <map>
#define sqr(x) ((x)*(x))
#define PR pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
const ll INF = (1ULL<<63)-1;
const int inf=0x3f3f3f3f;
const int M=100010;
const int N=200010;
const ll MOD=1000000007;
const double eps=1e-3;
const double pi=acos(-1.0);
using namespace std;
vector<int> g
,gc
;//g是原图,gc是缩点后的图
int n,u,v,ans,cnt;
int vis
,col
,comp
,dp
;//dp储存该点到图的任意一点的最远距离,comp是该点属于缩点后的图的哪一点
void dfs(int u,int c,int rt) //缩点操作
{
if(vis[u]||col[u]!=c) return;
vis[u]=1;
comp[u]=rt;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
dfs(v,c,rt);
}
}
void DFS(int u,int fa)
{
int mx=0,mmx=0;//mx是点到图的任意一点的最远距离,mmx是次远距离
for(int i=0;i<gc[u].size();i++)
{
int v=gc[u][i];
if(v==fa) continue;//防止遍历回父节点
DFS(v,u);
mmx=max(mmx,dp[v]+1);
if(mmx>mx) swap(mmx,mx);
}
dp[u]=mx;
ans=max(ans,mx+mmx);//图的直径等于某个点的最远距离加上次远距离
}
int main()
{
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&col[i]);
for(i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);g[v].push_back(u);
}
for(i=1;i<=n;i++)
{
if(vis[i]==0) dfs(i,col[i],++cnt);
}
for(i=1;i<=n;i++)
{
for(j=0;j<g[i].size();j++)
{
int v=g[i][j];
if(comp[v]!=comp[i]) gc[comp[i]].push_back(comp[v]);
}
}
DFS(1,-1);
printf("%d\n",ans);
}
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
Anton is growing a tree in his garden. In case you forgot, the tree is a connected acyclic undirected graph.
There are n vertices in the tree, each of them is painted black or white. Anton doesn't like multicolored trees, so he wants to change
the tree such that all vertices have the same color (black or white).
To change the colors Anton can use only operations of one type. We denote it as paint(v), where v is
some vertex of the tree. This operation changes the color of all vertices u such that all vertices on the shortest path from v to u have
the same color (including v andu).
For example, consider the tree
and apply operation paint(3) to get the following:
Anton is interested in the minimum number of operation he needs to perform in order to make the colors of all vertices equal.
Input
The first line of the input contains a single integer n (1 ≤ n ≤ 200 000) —
the number of vertices in the tree.
The second line contains n integers colori (0 ≤ colori ≤ 1) —
colors of the vertices. colori = 0 means
that the i-th vertex is initially painted white, while colori = 1 means
it's initially painted black.
Then follow n - 1 line, each of them contains a pair of integers ui and vi (1 ≤ ui, vi ≤ n, ui ≠ vi) —
indices of vertices connected by the corresponding edge. It's guaranteed that all pairs (ui, vi) are
distinct, i.e. there are no multiple edges.
Output
Print one integer — the minimum number of operations Anton has to apply in order to make all vertices of the tree black or all vertices of the tree white.
Examples
input
11 0 0 0 1 1 0 1 0 0 1 1 1 2 1 3 2 4 2 5 5 6 5 7 3 8 3 9 3 10 9 11
output
2
input
4
0 0 0 0
1 22 3
3 4
output
0
题意:包含n个点的一棵树,每个点都有黑白两种颜色,每改变一个节点的颜色,他周围和它颜色相同的节点也变色(一整块颜色相同的点),求让这棵树变成同一种颜色的最小操作。
思路:利用连通量缩点,重新建图,求出最远两个节点的距离x,(x+1)/2就是答案
看了别人题解用模板写了个很挫的代码。。。
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>
using namespace std;
#define MAX_V 200005
int V;
int ans;
vector<int>G[MAX_V]; //原图
vector<int>rG[MAX_V]; //反向边图
vector<int>gc[MAX_V]; //缩点之后的图
vector<int>vs; //后序遍历顶点序列
bool used[MAX_V]; //访问标记
int cmp[MAX_V]; //所属强连通分量拓扑序
bool color[MAX_V]; //颜色
int dp[MAX_V]; //记录每个点到其他所有点中最远点的距离
void add_edge(int from,int to)
{
G[from].push_back(to);
rG[to].push_back(from);
}
void dfs(int v) //第一次dfs
{
used[v]=true;
for(int i=0;i<G[v].size();i++)
{
if(!used[G[v][i]])dfs(G[v][i]);
}
vs.push_back(v);
}
void rdfs(int v,int k) //第二次dfs
{
used[v]=true;
cmp[v]=k;
for(int i=0;i<rG[v].size();i++)
{
if(!used[rG[v][i]])rdfs(rG[v][i],k);
}
}
int scc()
{
memset(used,0,sizeof(used));
vs.clear();
for(int v=0;v<V;v++)
{
if(!used[v])dfs(v);
}
memset(used,0,sizeof(used));
int k=0;
for(int i=vs.size()-1;i>=0;i--)
{
if(!used[vs[i]])
{
rdfs(vs[i],k++);
}
}
return k;
}
void DFS(int u,int fa)
{
int mx=0,mmx=0;//mx是点到图的任意一点的最远距离,mmx是次远距离
for(int i=0;i<gc[u].size();i++)
{
int v=gc[u][i];
if(v==fa) continue;//防止遍历回父节点
DFS(v,u);
mmx=max(mmx,dp[v]+1);
if(mmx>mx) swap(mmx,mx);
}
dp[u]=mx;
ans=max(ans,mx+mmx);//图的直径等于某个点的最远距离加上次远距离
}
void init()
{
ans=0;
for(int i=0;i<MAX_V;i++)
{
G[i].clear();
rG[i].clear();
gc[i].clear();
}
vs.clear();
memset(used,0,sizeof(used));
memset(cmp,0,sizeof(cmp));
memset(color,0,sizeof(color));
memset(dp,0,sizeof(dp));
}
int main()
{
while(~scanf("%d",&V))
{
for(int i=0;i<V;i++)scanf("%d",&color[i]);
int f,t;
for(int i=0;i<V-1;i++)
{
scanf("%d%d",&f,&t);
if(color[f-1]==color[t-1]) //如果两点颜色一样就是无向边,颜色不一样就是有向边
{
add_edge(f-1,t-1);
add_edge(t-1,f-1);
}
else add_edge(f-1,t-1);
}
int h=scc();
//重新建图
for(int i=0;i<V;i++)
{
for(int j=0;j<G[i].size();j++)
{
int v=G[i][j];
if(cmp[v]!=cmp[i])
{
gc[cmp[v]].push_back(cmp[i]);
gc[cmp[i]].push_back(cmp[v]);
}
}
}
DFS(0,-1);
printf("%d\n",(ans+1)/2);
}
}下面是别人的代码:http://blog.csdn.net/pan1197349032/article/details/53217462
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <set>
#include <vector>
#include <map>
#define sqr(x) ((x)*(x))
#define PR pair<int,int>
#define MP make_pair
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define ll long long
const ll INF = (1ULL<<63)-1;
const int inf=0x3f3f3f3f;
const int M=100010;
const int N=200010;
const ll MOD=1000000007;
const double eps=1e-3;
const double pi=acos(-1.0);
using namespace std;
vector<int> g
,gc
;//g是原图,gc是缩点后的图
int n,u,v,ans,cnt;
int vis
,col
,comp
,dp
;//dp储存该点到图的任意一点的最远距离,comp是该点属于缩点后的图的哪一点
void dfs(int u,int c,int rt) //缩点操作
{
if(vis[u]||col[u]!=c) return;
vis[u]=1;
comp[u]=rt;
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
dfs(v,c,rt);
}
}
void DFS(int u,int fa)
{
int mx=0,mmx=0;//mx是点到图的任意一点的最远距离,mmx是次远距离
for(int i=0;i<gc[u].size();i++)
{
int v=gc[u][i];
if(v==fa) continue;//防止遍历回父节点
DFS(v,u);
mmx=max(mmx,dp[v]+1);
if(mmx>mx) swap(mmx,mx);
}
dp[u]=mx;
ans=max(ans,mx+mmx);//图的直径等于某个点的最远距离加上次远距离
}
int main()
{
int i,j;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&col[i]);
for(i=1;i<n;i++)
{
scanf("%d%d",&u,&v);
g[u].push_back(v);g[v].push_back(u);
}
for(i=1;i<=n;i++)
{
if(vis[i]==0) dfs(i,col[i],++cnt);
}
for(i=1;i<=n;i++)
{
for(j=0;j<g[i].size();j++)
{
int v=g[i][j];
if(comp[v]!=comp[i]) gc[comp[i]].push_back(comp[v]);
}
}
DFS(1,-1);
printf("%d\n",ans);
}
相关文章推荐
- Tarjan求强连通分量,缩点
- 强连通分量与缩点(Tarjan算法)(洛谷P3387)
- 【强连通分量缩点】【DFS】【动态规划】Urozero Autumn Training Camp 2016 Day 5: NWERC-2016 Problem B. British Menu
- 强连通分量——tarjan ->缩点
- 连通分量模板:tarjan: 求割点 && 桥 && 缩点 && 强连通分量 && 双连通分量 && LCA(近期公共祖先)
- 边连通分量/缩点-POJ3177-Redundant Paths
- 2017 乌鲁木齐赛区网络赛 Islands(【点强连通问题】【缩点+点强连通分量】)
- The Bottom of a Graph 强连通分量 缩点后 那些点的出度为0
- 图论--有向图强连通分量的标记及缩点模板
- 模板:强连通分量和缩点
- POJ3352(连通分量缩点)
- POJ-1236(有向图强连通分量 + 缩点 + 加边使得整个图强连通)
- 训练赛 Grouping(强连通分量缩点 + DAG求最长路)
- Codeforces 427C - Checkposts 极大连通分量Tarjan算法模板题(STL实现)
- Codeforces 734E. Anton and Tree By Assassin 缩点+树的最大直径
- UVA 11324 有向图强连通分量缩点得SCC图,并在其上求最长路径
- 训练赛 Grouping(强连通分量缩点 + DAG求最长路)
- Kosaraju算法求有向强连通分量,缩点后是DAG的拓扑序列(从小到大)
- POJ2186 (强连通分量缩点后出度为0的分量内点个数)
- Codeforces734E【缩点+树的直径】