题目链接
题目大意:现在有N个城市,标号为1的为我们的首都,我们现在想着从首都能够到达任意一个城市,现在给出你M个边,也就是城市之间的道路,其中这些道路有好的不需要修理,有坏了的需要修理,问你最少需要修几条路才能使我们能够从首都到达任意一个城市,注意给出的边均为单向边
思路:这里是最小树型图的思想,在网上看了代码还有的是直接的搜索,好像不大好,
更多的是朱刘算法的最小树型图吧,但是路径的输出比较难,这个地方搞了很久,个人也是比较菜
我们标记一个可能会删掉的边,根据那个图中的我们找出来最小的边集合后可能会出现环,环中的某些边不是需要的,
代码:
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<vector>
#define ll long long
using namespace std;
const int maxn=2001005;
const int inf=1000000005;
struct Edge
{
int u,v,cost,id;
int w;
} e[maxn];
struct Cancel
{
int pre,id;
} cancel[maxn];
int vis[maxn],pre[maxn],id[maxn],in[maxn];
int useE[maxn],preid[maxn];
void addedge(int u,int v,int w,int id)
{
e[id].u=u;
e[id].v=v;
e[id].id=id;
e[id].cost=e[id].w=w;
}
int Directed_MST(int root,int Nv,int Ne)
{
int ret=0,total=Ne;
while(true)
{
for(int i=0; i<Nv; i++)
in[i]=inf;
memset(pre,-1,sizeof(pre));
for(int i=0; i<Ne; i++)
{
int u=e[i].u,v=e[i].v;
if(e[i].cost<in[v]&&u!=v)
{
pre[v] = u;
in[v] = e[i].cost;
preid[v]=e[i].id;
}
}
for(int i=0; i<Nv; i++)
if(i!=root&&in[i]==inf)
return -1;
int cntnode=0;
memset(id,-1,sizeof(id));
memset(vis,-1,sizeof(vis));
in[root]=0;
for(int i=0; i<Nv; i++)
{
ret+=in[i];
int v=i;
if(i!=root) useE[preid[i]]++;
while(vis[v] != i && id[v] == -1 && v != root)
vis[v] = i,v = pre[v];
if(v!=root&&id[v]==-1)
{
for(int u = pre[v]; u != v; u = pre[u])
id[u] = cntnode;
id[v]=cntnode++;
}
}
if(cntnode==0)
break;
for(int i=0; i<Nv; i++)
if(id[i]==-1)
id[i]=cntnode++;
for(int i=0; i<Ne; i++)
{
int u=e[i].u;
int v = e[i].v;
e[i].u = id[u];
e[i].v = id[v];
if(e[i].u != e[i].v)
{
cancel[total].id=e[i].id;
cancel[total].pre=preid[v];
e[i].cost -= in[v];
e[i].id=total++;
}
}
Nv=cntnode;
root=id[root];
}
for(int i=total-1; i>=Ne; i--)
if(useE[i])
{
useE[cancel[i].pre]--;
useE[cancel[i].id]++;
}
return ret;
}
int main()
{
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
int n,m;
scanf("%d%d",&n,&m);
for(int i=0; i<m; i++)
{
int x,y,c;
scanf("%d%d%d",&x,&y,&c);
x--,y--;
addedge(x,y,c,i);
}
int Min=Directed_MST(0,n,m);
printf("%d\n",Min);
if(Min!=-1)
{
for(int i=0;i<m;i++)
if(useE[i]&&e[i].w)
printf("%d ",i+1);
}
return 0;
}