题目
题意:
给定一张n个点m条边的带权图,输出是否可以删去最多两条边,使得s与t不连通。有多种方案时输出权值最小的方案,没有则输出-1。
1
≤
n
≤
1
e
3
,
1
≤
m
≤
1
e
4
1≤n≤1e3,1≤m≤1e4
1≤n≤1e3,1≤m≤1e4
分析:
可以注意到n比较小,而且最多删两条,那就考虑能否枚举一条,再去尝试删去另一条。那我们枚举的这一条边一定是在s到t的一条路径上的,且这条路径上一定要删去一条边。所以我们先找到s到t的一条路径,枚举删去这条路径上的一条边,现在的问题就变成删去一条边,能否使得s与t不连通,很容易想到这条边就是s到t路径上的一条割边,所以我们再找一次s到t的路径(注意之前枚举的边被删去了),查看这条路径上是否有割边,如果有,那么这条边加上我们枚举的这一条就是一个答案了,找最小输出即可。
#include <iostream>
#include <vector>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn = 1e3+5;
struct edges{
int to,next;
ll val;
}edge[60005];
int head[maxn],cnt = 0;
int dfn[maxn],low[maxn],cntx = 1;
bool bridge[60005],del[60005];
int s,t;
vector<int> p,b;
int vis[maxn],flag;
void add(int x,int y,ll v)
{
edge[cnt].to = y;
edge[cnt].next = head[x];
edge[cnt].val = v;
head[x] = cnt ++;
}
void tarjan(int x,int in_edge)
{
dfn[x] = low[x] = cntx++;
for (int i = head[x]; i != -1; i = edge[i].next)
{
if( del[i] ) continue;
int t = edge[i].to;
if( !dfn[t] )
{
tarjan(t,i);
low[x] = min(low[x],low[t]);
if( low[t] > dfn[x] )
{
bridge[i] = bridge[i^1] = true;
b.push_back(i);
}
}else if( i != (in_edge^1) ) low[x] = min(low[x],dfn[t]);
}
}
void dfs(int x)
{
vis[x] = 1;
for (int i = head[x]; i != -1; i = edge[i].next)
{
if( del[i] ) continue;
int z = edge[i].to;
if( vis[z] ) continue;
if( z == t )
{
p.push_back(i);
flag = 1;
return;
}
dfs(z);
if( flag )
{
p.push_back(i);
return;
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
memset(head,-1,sizeof(head));
int n,m;
cin >> n >> m >> s >> t;
for (int i = 1; i <= m; i++)
{
ll x,y,v;
cin >> x >> y >> v;
add(x,y,v),add(y,x,v);
}
vector<int> tmp;
flag = 0;
dfs(s);
tmp = p;
p.clear();
memset(vis,0,sizeof(vis));
if( tmp.empty() )
{
cout << 0 << '\n';
cout << 0 << '\n';
return 0;
}
ll ans = 1e18;
vector<int> res;
for (int i = 0; i < tmp.size(); i++)
{
int z1 = tmp[i];
del[z1] = del[z1^1] = 1;
tarjan(s,0);
vector<int> tmpx;
flag = 0;
dfs(s);
tmpx = p;
p.clear();
if( tmpx.size() == 0 )
{
if( ans > edge[z1].val )
{
ans = edge[z1].val;
res.clear();
res.push_back(z1/2+1);
}
}else
{
for (int j = 0; j < tmpx.size(); j++)
{
int z2 = tmpx[j];
if( bridge[z2] )
{
if( ans > edge[z1].val + edge[z2].val )
{
ans = edge[z1].val + edge[z2].val;
res.clear();
res.push_back(z1/2+1);
res.push_back(z2/2+1);
}
}
}
}
memset(vis,0,sizeof(vis));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
cntx = 1;
for (int j = 0; j < b.size(); j++)
{
bridge[b[j]] = bridge[b[j]^1] = false;
}
b.clear();
del[z1] = del[z1^1] = 0;
}
if( ans == 1e18 ) cout << -1 << '\n';
else
{
cout << ans << '\n';
cout << res.size() << '\n';
for (int i = 0; i < res.size(); i++)
{
cout << res[i];
if( i == res.size() - 1 ) cout << '\n';
else cout << ' ';
}
}
return 0;
}