(有任何问题欢迎留言或私聊
(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;
}