给你一些点,再指定其中的一部分点并加上权值,问是否有一种方案,使得从指定的点中的某几个点开始对图遍历,能把整个图遍历完,并且权值最小。
tarjan缩点。
对于每一个强连通分量,我们就要那个权值最小作为权值即可。
缩完点后构图,统计入度。
如果一个强连通分量的入度为0且里面没有点有权值,那就输出no。
不然,每个入度为0的强连通分量的权值和就是答案。。。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
struct arr{
int x,y,w,next;
}edge[1000000];
int ls[10000];
int edge_m;
int s[10000];
int n,m,r;
int a[10000];
void add(int x,int y)//加边。
{
edge[++edge_m]=(arr){x,y,1,ls[x]},ls[x]=edge_m;
return;
}
int v[10000];
int dfn[10000];
int low[10000];
int scc[10000];
int small[10000];
int ans=0;
int num=0;
stack<int> sta;
void tarjan(int x)//tarjan求强连通分量。
{
sta.push(x);
num++;
dfn[x]=low[x]=num;
v[x]=1;
for (int i=ls[x];i;i=edge[i].next)
{
int y=edge[i].y;
if (dfn[y]==0)
{
tarjan(y);
low[x]=min(low[x],low[y]);
}
else
if (v[y]) low[x]=min(dfn[y],low[x]);
}
if (dfn[x]==low[x])
{
ans++;
while ((sta.top()!=x)&&(!sta.empty()))
{
int y=sta.top();
v[y]=0;
scc[y]=ans;
small[ans]=min(small[ans],a[y]);
sta.pop();
}
int y=sta.top();
v[y]=0;
scc[y]=ans;
small[ans]=min(small[ans],a[y]);
sta.pop();
}
}
int main()
{
scanf("%d",&n);
scanf("%d",&r);
memset(a,63,sizeof(a));
memset(small,63,sizeof(small));
for (int i=1;i<=r;i++)
{
int x,y;
scanf("%d%d",&x,&y);
a[x]=y;
}
scanf("%d",&m);
for (int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
for (int i=1;i<=n;i++)
if (dfn[i]==0)
tarjan(i);
for (int i=1;i<=m;i++)//统计各个强连通分量的入度。
{
int x=edge[i].x;
int y=edge[i].y;
if (scc[x]!=scc[y])
s[scc[y]]++;
}
for (int i=1;i<=n;i++)
if ((s[scc[i]]==0)&&(small[scc[i]]==small[0]))
{
printf("NO\n"),printf("%d",i);
return 0;
}
printf("YES\n");
int la=0;
for (int i=1;i<=ans;i++)
if (s[i]==0) la+=small[i];
printf("%d",la);
return 0;
}