Codeforces Round #364 F Break Up

题目链接 :点击打开链接

F. Break Up
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Again, there are hard times in Berland! Many towns have such tensions that even civil war is possible.

There are n towns in Reberland, some pairs of which connected by two-way roads. It is not guaranteed that it is possible to reach one town from any other town using these roads.

Towns s and t announce the final break of any relationship and intend to rule out the possibility of moving between them by the roads. Now possibly it is needed to close several roads so that moving from s to t using roads becomes impossible. Each town agrees to spend money on closing no more than one road, therefore, the total number of closed roads will beno more than two.

Help them find set of no more than two roads such that there will be no way betweens and t after closing these roads. For each road the budget required for its closure was estimated. Among all sets find such that the total budget for the closure of a set of roads is minimum.

Input

The first line of the input contains two integers n andm (2 ≤ n ≤ 1000,0 ≤ m ≤ 30 000) — the number of towns in Berland and the number of roads.

The second line contains integers s andt (1 ≤ s, t ≤ n,s ≠ t) — indices of towns which break up the relationships.

Then follow m lines, each of them contains three integersxi,yi andwi (1 ≤ xi, yi ≤ n,1 ≤ wi ≤ 109) — indices of towns connected by thei-th road, and the budget on its closure.

All roads are bidirectional. It is allowed that the pair of towns is connected by more than one road. Roads that connect the city to itself are allowed.

Output

In the first line print the minimum budget required to break up the relations betweens and t, if it is allowed to close no more than two roads.

In the second line print the value c (0 ≤ c ≤ 2) — the number of roads to be closed in the found solution.

In the third line print in any order c diverse integers from1 to m — indices of closed roads. Consider that the roads are numbered from1 to m in the order they appear in the input.

If it is impossible to make towns s andt disconnected by removing no more than 2 roads, the output should contain a single line -1.

If there are several possible answers, you may print any of them.

Examples
Input
6 7
1 6
2 1 6
2 3 5
3 4 9
4 6 4
4 6 5
4 5 1
3 1 3
Output
8
2
2 7
Input
6 7
1 6
2 3 1
1 2 2
1 3 3
4 5 4
3 6 5
4 6 6
1 5 7
Output
9
2
4 5
Input
5 4
1 5
2 1 3
3 2 1
3 4 4
4 5 2
Output
1
1
2
Input
2 3
1 2
1 2 734458840
1 2 817380027
1 2 304764803
Output
-1

题意:在一个无向图中有n(1000)个点,m条边(30000),其中可以存在重边和子环。再给出2个点S,T。问在最多去掉2条边的条件下,输出去掉的边的权值和最小的权值和和去掉的边数,边的编号(按输入的顺序编号).


思路:

          显然,如果S,T属于不同的连通集,那么肯定无法到达。所以,首先我们判断S,T是否相连。这个·只需一个dfs遍历图就能完成,由于是无向图,每个点只许经过一次,所以时间复杂度通常情况下<<n*m.

          当S,T连通时,记录他们所经过的边,这就可能是之后去掉的边之一(如果去掉的边没有包含这些边那么他们还是连通)。之后无向图求桥,判断从S到T的边是否为桥,如果是桥,则说明去掉桥后,S,T不再连通。否则,虽然整张图不再连通,但S,T仍然连通。这就是去掉一条边的情况。

          去掉两条边的情况,稍微复杂一点。因为去掉两条边的情况中,必然有一条是上述dfs出的一条边并且边数小于n,所以我们可以枚举dfs出的每条边将之删去。之后再进行dfs出从S到T的新路径,之后的过程就和上边的过程一下,用桥来求出第二条边。


#include<bits/stdc++.h>

using namespace std;

const int MAXV = 1005;

int dfs[MAXV],low[MAXV],head[MAXV];
bool isbridge[MAXV*30],vis[MAXV],cut[MAXV*30];
int cnt,EN;
int n,m,s,t,ans;
vector<int>st_path,st_ans,now_path;

struct Edge
{
    int from,to,nxt,w,ind;
}edge[MAXV*60];

void addedge(int cu,int cv,int w,int ind)
{
    edge[EN].from = cu;
    edge[EN].to = cv;
    edge[EN].nxt = head[cu];
    edge[EN].w = w;
    edge[EN].ind=ind;
    head[cu] = EN++;
}
void tarjan(int now, int pre)
{
    dfs[now] = low[now] = cnt++;
    for (int i = head[now]; i!=-1; i = edge[i].nxt)
    {
        int  next = edge[i].to,now_ind=edge[i].ind;
        if (  now_ind == pre || cut[now_ind] )  continue;
        if ( dfs[next] == 0 )
        {
             tarjan( next, now_ind );
             low[now] = min( low[now] , low[next] );
             if( dfs[now] < low[next] && dfs[now]<dfs[next])
             {
               isbridge[now_ind]=true;
             }
        }
        else
        {
            low[now] = low[now]<dfs[next]? low[now]: dfs[next];
        }
    }
}
void find_bridge()
{
    memset(dfs,0,sizeof(dfs));
    memset(low,0,sizeof(low));
    memset(isbridge,false,sizeof(isbridge));
    cnt=0;
    for(int i=1;i<=n;i++)
    {
        if(!dfs[i])
            tarjan(i,0);
    }
}
bool DFS(int now,int pre)
{
    if(now == t) return true;
    vis[now]=true;
    for(int i = head[now]; i!= -1 ;i = edge[i].nxt)
    {
        int next=edge[i].to,now_ind=edge[i].ind;
        if( now_ind == pre  || vis[next] || cut[now_ind] ) continue ;
        if(DFS(next,now_ind))
        {
            st_path.push_back(now_ind);
            return true;
        }
    }
    return false;
}
bool find_path()
{
    st_path.clear();
    memset(vis,false,sizeof(vis));
    return DFS(s,0);
}

int solve()
{
    memset(cut,false,sizeof(cut));
    st_ans.clear();
    ans=2e9+5;
    if(!find_path())
    {
        puts("0\n0");
        return 0;
    }
    find_bridge();
    for(int i=0;i<st_path.size();i++)
    {
        int judge=st_path[i];
        if(isbridge[judge]&&edge[judge*2].w<=ans)
        {
            st_ans.clear();
            st_ans.push_back(judge);
            ans=edge[judge*2].w;
        }
    }
    now_path.clear();
    for(int i=0;i<st_path.size();i++)
    {
        now_path.push_back(st_path[i]);
    }
    for(int i=0;i<now_path.size();i++)
    {
        int flag=now_path[i];
        cut[flag]=true;
        if(!find_path()) {cut[flag]=false;continue;}
        find_bridge();
        for(int j=0;j<st_path.size();j++)
        {
            int judge=st_path[j];
            if(isbridge[judge]&&(edge[judge*2].w+edge[flag*2].w)<=ans)
            {
               st_ans.clear();
               st_ans.push_back(judge);
               st_ans.push_back(flag);
               ans=edge[judge*2].w+edge[flag*2].w;
            }
        }
        cut[flag]=false;
    }
    return 1;
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        EN=1;
        memset(head,-1,sizeof(head));
	    scanf("%d %d", &s, &t);
	    int u,v,w;
	    for (int i = 1; i <= m; i++)
	    {
		    scanf("%d %d %d", &u, &v, &w);
		   // if (u != v)
		    {
		       addedge(u,v,w,i);
		       addedge(v,u,w,i);
		    }
        }
        if(!solve())
            continue;
        if(!st_ans.size())
        {
             puts("-1");
             continue;
        }
        cout<<ans<<endl<<st_ans.size()<<endl;
        for(int i=0;i<st_ans.size();i++)
        {
          cout<<st_ans[i]<<" ";
        }
    }
    return 0;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值