Codeforces Round #364 (Div. 2) F. Break Up(割边)

来源:互联网 发布:软件license管理器 编辑:程序博客网 时间:2024/06/11 04:40

参考题解:http://codeforces.com/contest/701/problem/F
感觉这题思路并不难,但是编码不太容易。

思路:

  • 首先判断图的连通性,看S和T是否在同一个连通块里面,如果不在的话,就直接输出结果。如果在一个连通块里面的话,再进行后续的判断。

  • 当S和T连通的时候,求出两点间的一条路径,因为最多只能删除删除两条边,如果有解的话,肯定有一条边在这个路径里。如果S和T只有一条路径,那肯定就是这一条路径,如果S和T有两条不相交的路径,肯定每个路径要删除一条边。如果S和T之间超过两条不相交路径,肯定无解了。

  • 先枚举找到这条路径的每条边,如果存在割边的话,就更新答案,枚举完路径上的边之后。然后再枚举删除这条路径的每条边,然后再找一条S和T之间的路径,看这条路径上有没有割边,有的话,就更新答案。
#include <bits/stdc++.h>using namespace std;const int MAXN = 1111;const int MAXM = 66666;const int INF = 2e9+10;int Dfn[MAXN],Low[MAXN];struct Edge{    int to,next,w,id;}edge[MAXM];int head[MAXN];bool cut[MAXM],vis[MAXN],isBridge[MAXM];int s,t,n,m,cnt,tot;vector<int> path,ans,opath;void init(){    memset(head,-1,sizeof(head));    tot = 1;}void addedge(int u, int v, int w, int id){    edge[tot].to = v;    edge[tot].w = w;    edge[tot].id = id;    edge[tot].next=  head[u];    head[u] = tot++;}bool dfs(int u, int pre){    if(u == t) return true;    for(int i = head[u]; i != -1; i = edge[i].next)    {        int v = edge[i].to;        int id = edge[i].id;        if(vis[v] || cut[id] || id == pre) continue;        vis[v] = true;        if(dfs(v,id))        {            path.push_back(id);            return true;        }    }    return false;}bool findPath(){    memset(vis,false,sizeof(vis));    path.clear();    vis[s] = true;    return dfs(s,0);}void Tarjan(int u, int pre){    Dfn[u] = Low[u] = cnt++;    for(int i = head[u]; i != -1; i = edge[i].next)    {        int v = edge[i].to;        int id = edge[i].id;        if(cut[id]) continue;        if(!Dfn[v])        {            Tarjan(v,id);            Low[u] = min(Low[u],Low[v]);            if(Dfn[u] < Low[v])                isBridge[id] = true;        }        else if(id != pre)            Low[u] = min(Low[u],Dfn[v]);    }}void findBridge(){    memset(Dfn,0,sizeof(Dfn));    memset(Low,0,sizeof(Low));    memset(isBridge,false,sizeof(isBridge));    cnt = 0;    for(int i = 1; i <= n; ++i)        if(!Dfn[i])            Tarjan(i,0);}void solve(){    memset(cut,false,sizeof(cut));    int res = INF;    ans.clear();    //dfs判定图的连通性,顺便记录s-t的路径    if(!findPath())    {        puts("0\n0");        return;    }    //求割边    findBridge();    int nb;    //如果s-t的路径上有割边,去掉这个割边就可以使s-t不连通    for(int i = 0; i < path.size(); ++i)    {        nb = path[i];        if(isBridge[nb] && edge[nb*2].w <= res)        {            ans.clear();            ans.push_back(nb);            res = edge[nb*2].w;        }    }    opath.clear();    opath.insert(opath.begin(),path.begin(),path.end());    //枚举刚才找到的那条路径的每条边,删除这条边后再找桥    //即找两条边的最小花费    for(int i = 0; i < opath.size(); ++i)    {        nb = opath[i];        cut[nb] = true;        if(!findPath())        {            cut[nb] = false;            continue;        }        findBridge();        for(int j = 0; j < path.size(); ++j)        {            int onb = path[j];            if(isBridge[onb] && (edge[onb*2].w + edge[nb*2].w) <= res)            {                ans.clear();                ans.push_back(nb);                ans.push_back(onb);                res = edge[onb*2].w + edge[nb*2].w;            }        }        cut[nb] = false;    }    //如果一条边都没找到,就无解喽    if(ans.size())    {        printf("%d\n%d\n",res,ans.size());        for(int x : ans)            printf("%d ",x);    }    else        puts("-1");}int main(){    init();    int u,v,w;    scanf("%d %d",&n,&m);    scanf("%d %d",&s,&t);    for(int i = 1; i <= m; ++i)    {        scanf("%d %d %d",&u,&v,&w);        addedge(u,v,w,i);        addedge(v,u,w,i);    }    solve();    return 0;}
原创粉丝点击