/*给你有向图,有些边是可以直接走的,有些边是修之后才可以走,现在要想从1能到达所有的点,问你至少要修多少条路。
解:现把 可以直接 走的边加进来,缩点,因为(1<n,m<1e6)。
然后从1点bfs,每个点初始都为0,可以直接的标记为-1,要修的边标记为边的编号,当再有不修路就能到达的话又把它标记为-1,。
所以,如果路全部修之后好不能到达,则有些点还为0。
点的标记>0,则说明修路之后才能到达。
要记录边的编号,应该用数组模拟邻接链表。
*/
#include<cstdio>
#include<cstring>
#include<iostream>
#define N 100030
using namespace std;
int head[N];
int n,m,x,y;
int dfn[N],low[N],instack[N],num[N],edge[N],f[N],o[N],top,D,now,ans;
bool inst[N];
struct Node
{
int u,v,f;
int next;
}ed[N];
void tarjan(int i)
{
dfn[i]=low[i]=++D;
inst[i]=1,instack[++top]=i;
for (int p=head[i]; p; p=ed[p].next)
{
int j=ed[p].v;
if(ed[p].f)continue;
if (!dfn[j]) tarjan(j),low[i]=min(low[i],low[j]);
else if (inst[j]) low[i]=min(low[i],dfn[j]);
}
if (low[i]==dfn[i])
{
now++;
int k;
do k=instack[top--],inst[k]=0,num[k]=now;
while (k!=i);
}
}
void bfs(int x)
{
int h=0,t=1;
f[1]=x;
edge[x]=-1;
while (h<t)
{
int i=f[++h];
for (int p=head[i]; p; p=ed[p].next)
{
//int j=vv[p];
int j=ed[p].v;
if (!edge[j]) edge[j]=ed[p].f ?p:-1,f[++t]=j;
else if (edge[j]>0 && !ed[p].f) edge[j]=-1;
}
}
}
void init()
{
memset(head,0,sizeof(head));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(edge,0,sizeof(edge));
top=0;
D=0;
now=0;
}
void add(int u,int v,int f,int e)
{
ed[e].u=u;
ed[e].v=v;
ed[e].f=f;
ed[e].next=head[u];
head[u]=e;
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
while(scanf("%d%d",&n,&m)!=EOF)
{
init();
int u,v,f;
for (int i=1; i<=m; i++)
{
cin>>u>>v>>f;
add(u,v,f,i);
}
for (int i=1; i<=n; i++)
if (!dfn[i])
tarjan(i);
memset(head,0,sizeof(head));
for (int i=1; i<=m; i++)
{
//int x=num[uu[i]],y=num[vv[i]];
//vv[i]=y;
// if (x!=y) next[i]=head[x],head[x]=i;
int x=num[ed[i].u];
int y=num[ed[i].v];
int f=ed[i].f;
if(x!=y)
{
add(x,y,f,i);
}
}
bfs(num[1]);
ans=0;
for (int i=1; i<=now; i++)
if (edge[i]>0)
o[++ans]=edge[i];
for (int i=1; i<=now; i++)
if (!edge[i])
ans=-1;
printf("%d\n",ans);
for (int i=1; i<=ans; i++)
printf("%d%s",o[i],i<ans?" ":"\n");
}
return 0;
}
cf(tarjan运用+链表)
最新推荐文章于 2022-05-17 22:42:54 发布