CF240E Road Repairs(最小树形图-记录路径)

A country named Berland has n cities. They are numbered with integers from 1 to n. City with index 1 is the capital of the country. Some pairs of cities have monodirectional roads built between them. However, not all of them are in good condition. For each road we know whether it needs repairing or not. If a road needs repairing, then it is forbidden to use it. However, the Berland government can repair the road so that it can be used.

Right now Berland is being threatened by the war with the neighbouring state. So the capital officials decided to send a military squad to each city. The squads can move only along the existing roads, as there's no time or money to build new roads. However, some roads will probably have to be repaired in order to get to some cities.

Of course the country needs much resources to defeat the enemy, so you want to be careful with what you're going to throw the forces on. That's why the Berland government wants to repair the minimum number of roads that is enough for the military troops to get to any city from the capital, driving along good or repaired roads. Your task is to help the Berland government and to find out, which roads need to be repaired.

Input

The first line contains two space-separated integers n and m (1 ≤ n, m ≤ 105) — the number of cities and the number of roads in Berland.

Next m lines contain three space-separated integers ai, bi, ci (1 ≤ ai, bi ≤ n, ai ≠ bi, 0 ≤ ci ≤ 1), describing the road from city ai to city bi. If ci equals 0, than the given road is in a good condition. If ci equals 1, then it needs to be repaired.

It is guaranteed that there is not more than one road between the cities in each direction.

Output

If even after all roads are repaired, it is still impossible to get to some city from the capital, print  - 1. Otherwise, on the first line print the minimum number of roads that need to be repaired, and on the second line print the numbers of these roads, separated by single spaces.

The roads are numbered starting from 1 in the order, in which they are given in the input.

If there are multiple sets, consisting of the minimum number of roads to repair to make travelling to any city from the capital possible, print any of them.

If it is possible to reach any city, driving along the roads that already are in a good condition, print 0 in the only output line.

Examples

Input
3 2
1 3 0
3 2 1
Output
1
2
Input
4 4
2 3 0
3 4 0
4 1 0
4 2 1
Output
-1
Input
4 3
1 2 0
1 3 0
1 4 0
Output
0

题解:
题目意思是:给你有向路径,0表示可以走,1表示这条路需要修复才能走,问你要让1号点能走到所有点的最小花费是多少。
思路:最小树形图就是最小代价,输出边的话,就是在zhuliu算法中的缩环的过程中记录需要增加的边和要删除的边,最后倒着处理一遍,剩下的边就是最小树形图上的边。
我们字需要输出边的类型为1的边即可。

参考代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>
#define pil pair<int,ll>
#define mkp make_pair
const int INF=0x3f3f3f3f;
const int maxn=1e6+10;
struct Edge{
    int x,y,w;
    int id,real;
} edge[maxn];
int vis[maxn],id[maxn],in[maxn],pre[maxn];
int lastEdge[maxn],used[maxn];
int addEdge[maxn],delEdge[maxn];
int zhuliu(int root,int n,int m)
{
    int res=0,edgeNum=m;
    while(true)
    {
        for(int i=1;i<=n;++i) in[i]=INF;
        for(int i=1;i<=m;++i)//找到每个点的最小入边及其编号 
        {
            int x=edge[i].x,y=edge[i].y;
            if(edge[i].w<in[y] && x!=y)
            {
                pre[y]=x;
                in[y]=edge[i].w;
                lastEdge[y]=edge[i].id;
            }
        }
        for(int i=1;i<=n;++i)//判断是否可以形成最小树形图 
        {
            if(i==root) continue;
            if(in[i]==INF) return -1;    
        }
        int cnt=0; in[root]=0;
        memset(id,-1,sizeof id);
        memset(vis,-1,sizeof vis);
        for(int i=1;i<=n;++i)
        {
            res+=in[i];
            if(i!=root) used[lastEdge[i]]++;
            int y=i;
            while(vis[y]!=i&&id[y]==-1&&y!=root)
            {
                vis[y]=i;
                y=pre[y];
            }
            if(y!=root && id[y]==-1)
            {
                cnt++;
                for(int x=pre[y];x!=y;x=pre[x]) id[x]=cnt;
                id[y]=cnt;    
            }
        }
        
        if(cnt==0) break;
        for(int i=1;i<=n;++i)//独立点 
            if(id[i]==-1) id[i]=++cnt;
        
        for(int i=1;i<=m;++i)
        {
            int x=edge[i].x,y=edge[i].y;
            edge[i].x=id[x];edge[i].y=id[y];
            if(id[x]!=id[y])    
            {
                edge[i].w-=in[y];
                delEdge[++edgeNum]=lastEdge[y];
                addEdge[edgeNum]=edge[i].id;
                edge[i].id=edgeNum;    
            }
        }
        n=cnt;
        root=id[root];
    }
    
    for(int i=edgeNum;i>m;--i)
    {
        if(used[i])
        {
            --used[delEdge[i]];
            ++used[addEdge[i]];
        }
    }
    return res;
}

int main()
{
    freopen("input.txt","r",stdin);
    freopen("output.txt","w",stdout);
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d%d",&edge[i].x,&edge[i].y,&edge[i].w);
        edge[i].id=i;
        edge[i].real=edge[i].w;    
    }
    
    int res=zhuliu(1,n,m);
    if(res==-1||res==0) printf("%d\n",res);
    else
    {
        printf("%d\n",res);
        for(int i=1;i<=m;++i)
        {
            if(used[i]&&edge[i].real)
                printf("%d ",i);
        }
        puts("");
    }
    
    return 0;    
}
View Code

 

转载于:https://www.cnblogs.com/songorz/p/11559426.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值