您的位置:首页 > 其它

hdu 1827 有向图缩点看度数

2014-04-20 17:06 351 查看
题意:给一个有向图,选最少的点(同时最小价值),从这些点出发可以遍历所有。

思路:先有向图缩点,成有向树,找入度为0的点即可。

下面给出有向图缩点方法:

用一个数组SCC记录即可,重新编号,1....num,具体方法如下代码详见。

#include<iostream>
#include<cstdio>
#include<vector>
#include<stack>
using namespace std;
int n,m;
vector<vector<int> >v(10010);
int vis[10010];int dfn[10010];int low[10010];int times=0;
int num=0;
int instack[10010];stack<int>s;   //有向图的连通性,用栈。
int scc[1010]; int w[1010]; int neww[1010];
int ind[1010];
void tarjarn(int u)
{
dfn[u]=low[u]=++times;
instack[u]=1;
s.push(u);
for(int i=0;i<v[u].size();i++)
{
int vv=v[u][i];
if(!vis[vv])
{
vis[vv]=1;
tarjarn(vv);
if(low[vv]<low[u])low[u]=low[vv];  //孩子可以到达,我必然也可以到达。
}
else if(instack[vv])      //注意,更新时要有在栈中条件,代表该孩子(其实是祖先)我能到达,而且是属于当前SCC。
{
if(dfn[vv]<low[u])low[u]=dfn[vv]; //能到达的祖先,所以更新。
}
}
if(dfn[u]==low[u])
{
num++;int cur;
int min=w[u];   //找这个SCC权最小的权。
do
{
cur=s.top();
if(w[cur]<min)min=w[cur];
s.pop();
instack[cur]=0;
scc[cur]=num;
}while(cur!=u);
neww[num]=min;
}
}
int main()
{
while(~scanf("%d %d",&n,&m))
{
int ta,tb;
for(int i=0;i<=n;i++)
{
v[i].clear();
neww[i]=ind[i]=w[i]=instack[i]=dfn[i]=low[i]=vis[i]=0;
}
times=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
}
for(int i=0;i<m;i++)
{
scanf("%d %d",&ta,&tb);
v[ta].push_back(tb);
}
num=0;
for(int i=1;i<=n;i++)
{
if(!vis[i])
{   vis[i]=1;
tarjarn(i);
}
}
int sum=0;int count=0;
for(int i=1;i<=n;i++)           //遍历边。
{
for(int j=0;j<v[i].size();j++)
{
if(scc[i]!=scc[v[i][j]])
{
ind[scc[v[i][j]]]++;
}
}
}
for(int i=1;i<=num;i++)
{
if(ind[i]==0)
{
sum+=neww[i];
count++;
}
}
printf("%d %d\n",count, sum);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: