CSU-2133:balabala小魔法箱-湖南多校赛第八场---求大佬hack

(有任何问题欢迎留言或私聊

(ps:本来昨晚就写好了,然后被大佬hack了,现在才勉强敢写,欢迎大佬来hack我

题目:传送门

 题目意思很简单,就是给你n个点,m条边的无向图。规定一个起点和终点。然后m条边有的边标号为1,其他为0。问是否存在一条从起点到终点的路径且路径经过至少一条标号为1的边。(注意每条边只能走一次,点不做要求)

思路:

 听了大佬的话得知正解是缩点写,(然后我用了最短路,费用流,最大流,dfs全没过,一定是我自己太菜了)。


正解:

  • tarjan缩点,每个点的权值为环内边的权值和
  • 重新建图,跑bfs或dfs都行。我写的是bfs。
  • 这题还是有一些细节的,建议大家根据这个思路先自己敲敲,遇到问题可以再看我的代码。不过我的代码可能是错的哦。。求hack

闲话:

 知道正解是缩点,然后半个月前写了 一道tarjan被缩点折磨过 ,我脑抽地选择了求点双联通分量的方法缩点。
 导致代码非常复杂,写的心累。。。。然后当晚还被hack了。。。发现是割点的问题没处理好,接着处理了一下割点的情况,,写着又累又复杂。。。。。
 结果还是有bug。虽然还是过了,可能数据没有涉及这方面。就是有一种情况是从起点出发走到终点再从终点走出去回到终点。这种情况不好判断。。。。


 最后发现用最普通的缩点方法就行了。而且用这种方法,上面的问题都解决了。这代码是在我最初ac的代码基础上改的,写的又臭又长。。。


AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
const int N = 100005;
struct lp{//无数次想用vector建图,因为之前不是这种写法,之前想排个序,让边权为1的先访问。。很难受,后来发现不用
    int v,w,nex;
}cw[N*2];
struct edge{
    int u;
    int v;
    int w;
}now,aa;
int stak[N],top;
int head[N],vis[N],dfn[N],low[N],qltMap[N];
int n,m,tot,qltNum,vs,vt,inde;
int val[N];
vector<pair<int,int> > g[N];//本来不想用pair的,无奈
void dfs(int u,int fa,int fae){
    dfn[u]=low[u]=++inde;
    vis[u]=1;int v;
    stak[++top]=u;
    for(int i=head[u];~i;i=cw[i].nex){
        int v=cw[i].v;
        if(fae!=-2&&(fae==(i^1))){//或者v==fa
            continue;
        }
        if(!vis[v]){
            dfs(v,u,i);
            low[u]=min(low[u],low[v]);
            //if(low[v] > dfn[u]) bridge
        }else if(vis[v]==1){
            low[u]=min(low[u],dfn[v]);
        }
    }
    if(low[u]==dfn[u]){
        qltNum++;
         do{
            v=stak[top--];
            qltMap[v]=qltNum;
        }while(v!=u);
    }
}
void tarjan(){
    for(int i=1;i<=n;++i){
        if(!vis[i]){
            dfs(i,-1,-2);
        }
    }
}
inline void add(int a,int b,int c){
    cw[++tot].v=b;cw[tot].nex=head[a];cw[tot].w=c;
    head[a]=tot;
}
inline void init(){
    memset(head, -1, sizeof(head));
    tot=-1;inde=qltNum=top=0;
    memset(dfn,0,sizeof(dfn));
    memset(low,0,sizeof(low));
    memset(vis,0,sizeof(vis));
    memset(val,0,sizeof(val));
    memset(qltMap,0,sizeof(qltMap));
    for(int i=0;i<=n;++i){
        g[i].clear();
    }
}
void bfs(int vs,int vt){
    queue<edge>Q;
    aa.u=vs;aa.v=val[vs];
    Q.push(aa);
    memset(vis,0,sizeof(vis));
    vis[vs]=1;
    int flag=0;
    while(!Q.empty()){
        now=Q.front();Q.pop();
        int u=now.u;
        for(int i=0;i<g[u].size();++i){
            int v=g[u][i].first;
            pii tmp = g[u][i];
            aa.u=v;aa.v=now.v;
            if(val[v]||tmp.second)aa.v=1;;
            if(v==vt){
                if(aa.v)flag=1;
                else flag=-1;
                break;
            }
            if(vis[v])continue;
            vis[v]=1;
            Q.push(aa);
        }
        if(flag)break;
    }
    if(flag==1)printf("YES\n");
    else printf("NO\n");
}
int main(){
    int T, a, b, c;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        init();
        for(int i = 1; i <= m; i++) {
            scanf("%d%d%d", &a, &b, &c);
            add(a, b, c);
            add(b, a, c);
        }
        scanf("%d%d",&vs,&vt);
        tarjan();
        for(int i=1;i<=n;++i){
            for(int j=head[i];~j;j=cw[j].nex){
                if(qltMap[i]==qltMap[cw[j].v]){
                    val[qltMap[i]]+=cw[j].w;//缩点后的权值
                    continue;
                }//重新建图
                g[qltMap[i]].push_back(make_pair(qltMap[cw[j].v],cw[j].w));
            }
        }
        if(qltMap[vs]==qltMap[vt]){//直接判断同一联通块的情况
            if(val[qltMap[vs]])printf("YES\n");
            else printf("NO\n");
            continue;
        }
        bfs(qltMap[vs],qltMap[vt]);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值